Adding joinable threads, and gpr_thd_join.
diff --git a/BUILD b/BUILD
index e5822c7..ccff9c0 100644
--- a/BUILD
+++ b/BUILD
@@ -72,6 +72,7 @@
"src/core/support/sync.c",
"src/core/support/sync_posix.c",
"src/core/support/sync_win32.c",
+ "src/core/support/thd.c",
"src/core/support/thd_posix.c",
"src/core/support/thd_win32.c",
"src/core/support/time.c",
diff --git a/Makefile b/Makefile
index fad9eb2..4e99231 100644
--- a/Makefile
+++ b/Makefile
@@ -2334,6 +2334,7 @@
src/core/support/sync.c \
src/core/support/sync_posix.c \
src/core/support/sync_win32.c \
+ src/core/support/thd.c \
src/core/support/thd_posix.c \
src/core/support/thd_win32.c \
src/core/support/time.c \
@@ -2428,6 +2429,7 @@
$(OBJDIR)/$(CONFIG)/src/core/support/sync.o:
$(OBJDIR)/$(CONFIG)/src/core/support/sync_posix.o:
$(OBJDIR)/$(CONFIG)/src/core/support/sync_win32.o:
+$(OBJDIR)/$(CONFIG)/src/core/support/thd.o:
$(OBJDIR)/$(CONFIG)/src/core/support/thd_posix.o:
$(OBJDIR)/$(CONFIG)/src/core/support/thd_win32.o:
$(OBJDIR)/$(CONFIG)/src/core/support/time.o:
diff --git a/build.json b/build.json
index 1e7ab96..06adfee 100644
--- a/build.json
+++ b/build.json
@@ -337,6 +337,7 @@
"src/core/support/sync.c",
"src/core/support/sync_posix.c",
"src/core/support/sync_win32.c",
+ "src/core/support/thd.c",
"src/core/support/thd_posix.c",
"src/core/support/thd_win32.c",
"src/core/support/time.c",
diff --git a/include/grpc/support/thd.h b/include/grpc/support/thd.h
index 64d5bed..8126992 100644
--- a/include/grpc/support/thd.h
+++ b/include/grpc/support/thd.h
@@ -52,9 +52,8 @@
/* Thread creation options. */
typedef struct {
- int flags; /* Flags below can be set here. Default value 0. */
+ int flags; /* Opaque field. Get and set with accessors below. */
} gpr_thd_options;
-/* No flags are currently defined. */
/* Create a new thread running (*thd_body)(arg) and place its thread identifier
in *t, and return true. If there are insufficient resources, return false.
@@ -66,9 +65,25 @@
/* Return a gpr_thd_options struct with all fields set to defaults. */
gpr_thd_options gpr_thd_options_default(void);
+/* Set the thread to become detached on startup - this is the default. */
+void gpr_thd_options_set_detached(gpr_thd_options *options);
+
+/* Set the thread to become joinable - mutually exclusive with detached. */
+void gpr_thd_options_set_joinable(gpr_thd_options *options);
+
+/* Returns non-zero if the option detached is set. */
+int gpr_thd_options_is_detached(const gpr_thd_options *options);
+
+/* Returns non-zero if the option joinable is set. */
+int gpr_thd_options_is_joinable(const gpr_thd_options *options);
+
/* Returns the identifier of the current thread. */
gpr_thd_id gpr_thd_currentid(void);
+/* Blocks until the specified thread properly terminates.
+ Calling this on a detached thread has unpredictable results. */
+void gpr_thd_join(gpr_thd_id t);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/core/support/thd.c b/src/core/support/thd.c
new file mode 100644
index 0000000..ec308f3
--- /dev/null
+++ b/src/core/support/thd.c
@@ -0,0 +1,66 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Posix implementation for gpr threads. */
+
+#include <memory.h>
+
+#include <grpc/support/thd.h>
+
+enum {
+ GPR_THD_JOINABLE = 1
+};
+
+gpr_thd_options gpr_thd_options_default(void) {
+ gpr_thd_options options;
+ memset(&options, 0, sizeof(options));
+ return options;
+}
+
+void gpr_thd_options_set_detached(gpr_thd_options *options) {
+ options->flags &= ~GPR_THD_JOINABLE;
+}
+
+void gpr_thd_options_set_joinable(gpr_thd_options *options) {
+ options->flags |= GPR_THD_JOINABLE;
+}
+
+int gpr_thd_options_is_detached(const gpr_thd_options *options) {
+ if (!options) return 1;
+ return (options->flags & GPR_THD_JOINABLE) == 0;
+}
+
+int gpr_thd_options_is_joinable(const gpr_thd_options *options) {
+ if (!options) return 0;
+ return (options->flags & GPR_THD_JOINABLE) == GPR_THD_JOINABLE;
+}
diff --git a/src/core/support/thd_posix.c b/src/core/support/thd_posix.c
index f50ea58..7bf5272 100644
--- a/src/core/support/thd_posix.c
+++ b/src/core/support/thd_posix.c
@@ -68,7 +68,11 @@
a->arg = arg;
GPR_ASSERT(pthread_attr_init(&attr) == 0);
- GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0);
+ if (gpr_thd_options_is_detached(options)) {
+ GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0);
+ } else {
+ GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) == 0);
+ }
thread_started = (pthread_create(&p, &attr, &thread_body, a) == 0);
GPR_ASSERT(pthread_attr_destroy(&attr) == 0);
if (!thread_started) {
@@ -78,14 +82,12 @@
return thread_started;
}
-gpr_thd_options gpr_thd_options_default(void) {
- gpr_thd_options options;
- memset(&options, 0, sizeof(options));
- return options;
-}
-
gpr_thd_id gpr_thd_currentid(void) {
return (gpr_thd_id)pthread_self();
}
+void gpr_thd_join(gpr_thd_id t) {
+ pthread_join(t, NULL);
+}
+
#endif /* GPR_POSIX_SYNC */
diff --git a/src/core/support/thd_win32.c b/src/core/support/thd_win32.c
index 347cad5..f92fb64 100644
--- a/src/core/support/thd_win32.c
+++ b/src/core/support/thd_win32.c
@@ -31,7 +31,7 @@
*
*/
-/* Posix implementation for gpr threads. */
+/* Windows implementation for gpr threads. */
#include <grpc/support/port_platform.h>
@@ -40,47 +40,81 @@
#include <windows.h>
#include <string.h>
#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
#include <grpc/support/thd.h>
-struct thd_arg {
+#if defined(_MSC_VER)
+#define thread_local __declspec(thread)
+#elif defined(__GNUC__)
+#define thread_local __thread
+#else
+#error "Unknown compiler - please file a bug report"
+#endif
+
+struct thd_info {
void (*body)(void *arg); /* body of a thread */
void *arg; /* argument to a thread */
+ HANDLE join_event; /* if joinable, the join event */
+ int joinable; /* true if not detached */
};
+static thread_local struct thd_info *g_thd_info;
+
+/* Destroys a thread info */
+static destroy_thread(struct thd_info *t) {
+ if (t->joinable) CloseHandle(t->join_event);
+ gpr_free(t);
+}
+
/* Body of every thread started via gpr_thd_new. */
static DWORD WINAPI thread_body(void *v) {
- struct thd_arg a = *(struct thd_arg *)v;
- gpr_free(v);
- (*a.body)(a.arg);
+ g_thd_info = (struct thd_info *)v;
+ g_thd_info->body(g_thd_info->arg);
+ if (g_thd_info->joinable) {
+ BOOL ret = SetEvent(g_thd_info->join_event);
+ GPR_ASSERT(ret);
+ } else {
+ destroy_thread(g_thd_info);
+ }
return 0;
}
int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
const gpr_thd_options *options) {
HANDLE handle;
- DWORD thread_id;
- struct thd_arg *a = gpr_malloc(sizeof(*a));
- a->body = thd_body;
- a->arg = arg;
+ struct thd_info *info = gpr_malloc(sizeof(*info));
+ info->body = thd_body;
+ info->arg = arg;
*t = 0;
- handle = CreateThread(NULL, 64 * 1024, thread_body, a, 0, &thread_id);
- if (handle == NULL) {
- gpr_free(a);
+ if (gpr_thd_options_is_joinable(options)) {
+ info->joinable = 1;
+ info->join_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (info->join_event == NULL) {
+ gpr_free(info);
+ return 0;
+ }
} else {
- CloseHandle(handle); /* threads are "detached" */
+ info->joinable = 0;
}
- *t = (gpr_thd_id)thread_id;
+ handle = CreateThread(NULL, 64 * 1024, thread_body, info, 0, NULL);
+ if (handle == NULL) {
+ destroy_thread(info);
+ } else {
+ *t = (gpr_thd_id)info;
+ CloseHandle(handle);
+ }
return handle != NULL;
}
-gpr_thd_options gpr_thd_options_default(void) {
- gpr_thd_options options;
- memset(&options, 0, sizeof(options));
- return options;
+gpr_thd_id gpr_thd_currentid(void) {
+ return (gpr_thd_id)g_thd_info;
}
-gpr_thd_id gpr_thd_currentid(void) {
- return (gpr_thd_id)GetCurrentThreadId();
+void gpr_thd_join(gpr_thd_id t) {
+ struct thd_info *info = (struct thd_info *)t;
+ DWORD ret = WaitForSingleObject(info->join_event, INFINITE);
+ GPR_ASSERT(ret == WAIT_OBJECT_0);
+ destroy_thread(info);
}
#endif /* GPR_WIN32 */
diff --git a/test/core/support/thd_test.c b/test/core/support/thd_test.c
index c03a905..bb3d54a 100644
--- a/test/core/support/thd_test.c
+++ b/test/core/support/thd_test.c
@@ -60,12 +60,16 @@
gpr_mu_unlock(&t->mu);
}
+static void thd_body_joinable(void *v) { }
+
/* Test that we can create a number of threads and wait for them. */
static void test(void) {
int i;
gpr_thd_id thd;
+ gpr_thd_id thds[1000];
struct test t;
int n = 1000;
+ gpr_thd_options options = gpr_thd_options_default();
gpr_mu_init(&t.mu);
gpr_cv_init(&t.done_cv);
t.n = n;
@@ -79,6 +83,13 @@
}
gpr_mu_unlock(&t.mu);
GPR_ASSERT(t.n == 0);
+ gpr_thd_options_set_joinable(&options);
+ for (i = 0; i < n; i++) {
+ GPR_ASSERT(gpr_thd_new(&thds[i], &thd_body_joinable, NULL, &options));
+ }
+ for (i = 0; i < n; i++) {
+ gpr_thd_join(thds[i]);
+ }
}
/* ------------------------------------------------- */
diff --git a/vsprojects/vs2010/gpr.vcxproj b/vsprojects/vs2010/gpr.vcxproj
index f50f871..d23124c 100644
--- a/vsprojects/vs2010/gpr.vcxproj
+++ b/vsprojects/vs2010/gpr.vcxproj
@@ -166,6 +166,8 @@
</ClCompile>
<ClCompile Include="..\..\src\core\support\sync_win32.c">
</ClCompile>
+ <ClCompile Include="..\..\src\core\support\thd.c">
+ </ClCompile>
<ClCompile Include="..\..\src\core\support\thd_posix.c">
</ClCompile>
<ClCompile Include="..\..\src\core\support\thd_win32.c">
diff --git a/vsprojects/vs2010/gpr.vcxproj.filters b/vsprojects/vs2010/gpr.vcxproj.filters
index dffaf1e..1f87944 100644
--- a/vsprojects/vs2010/gpr.vcxproj.filters
+++ b/vsprojects/vs2010/gpr.vcxproj.filters
@@ -88,6 +88,9 @@
<ClCompile Include="..\..\src\core\support\sync_win32.c">
<Filter>src\core\support</Filter>
</ClCompile>
+ <ClCompile Include="..\..\src\core\support\thd.c">
+ <Filter>src\core\support</Filter>
+ </ClCompile>
<ClCompile Include="..\..\src\core\support\thd_posix.c">
<Filter>src\core\support</Filter>
</ClCompile>
diff --git a/vsprojects/vs2013/gpr.vcxproj b/vsprojects/vs2013/gpr.vcxproj
index 4b44cc6..e0fa68e 100644
--- a/vsprojects/vs2013/gpr.vcxproj
+++ b/vsprojects/vs2013/gpr.vcxproj
@@ -168,6 +168,8 @@
</ClCompile>
<ClCompile Include="..\..\src\core\support\sync_win32.c">
</ClCompile>
+ <ClCompile Include="..\..\src\core\support\thd.c">
+ </ClCompile>
<ClCompile Include="..\..\src\core\support\thd_posix.c">
</ClCompile>
<ClCompile Include="..\..\src\core\support\thd_win32.c">
diff --git a/vsprojects/vs2013/gpr.vcxproj.filters b/vsprojects/vs2013/gpr.vcxproj.filters
index dffaf1e..1f87944 100644
--- a/vsprojects/vs2013/gpr.vcxproj.filters
+++ b/vsprojects/vs2013/gpr.vcxproj.filters
@@ -88,6 +88,9 @@
<ClCompile Include="..\..\src\core\support\sync_win32.c">
<Filter>src\core\support</Filter>
</ClCompile>
+ <ClCompile Include="..\..\src\core\support\thd.c">
+ <Filter>src\core\support</Filter>
+ </ClCompile>
<ClCompile Include="..\..\src\core\support\thd_posix.c">
<Filter>src\core\support</Filter>
</ClCompile>