|
@@ -171,6 +171,7 @@ typedef long off_t;
|
|
|
#endif // !fileno MINGW #defines fileno
|
|
|
|
|
|
typedef HANDLE pthread_mutex_t;
|
|
|
+typedef DWORD pthread_key_t;
|
|
|
typedef HANDLE pthread_t;
|
|
|
typedef struct {
|
|
|
CRITICAL_SECTION threadIdSec;
|
|
@@ -285,6 +286,31 @@ static DWORD pthread_self(void)
|
|
|
{
|
|
|
return GetCurrentThreadId();
|
|
|
}
|
|
|
+
|
|
|
+int pthread_key_create(pthread_key_t *key, void (*_must_be_zero)(void*) /* destructor function not supported for windows */)
|
|
|
+{
|
|
|
+ assert(_must_be_zero == NULL);
|
|
|
+ if ((key!=0) && (_must_be_zero == NULL)) {
|
|
|
+ *key = TlsAlloc();
|
|
|
+ return (*key != TLS_OUT_OF_INDEXES) ? 0 : -1;
|
|
|
+ }
|
|
|
+ return -2;
|
|
|
+}
|
|
|
+
|
|
|
+int pthread_key_delete(pthread_key_t key)
|
|
|
+{
|
|
|
+ return TlsFree(key) ? 0 : 1;
|
|
|
+}
|
|
|
+
|
|
|
+int pthread_setspecific(pthread_key_t key, void * value)
|
|
|
+{
|
|
|
+ return TlsSetValue(key, value) ? 0 : 1;
|
|
|
+}
|
|
|
+
|
|
|
+void *pthread_getspecific(pthread_key_t key)
|
|
|
+{
|
|
|
+ return TlsGetValue(key);
|
|
|
+}
|
|
|
#endif // _WIN32
|
|
|
|
|
|
#define MD5_STATIC static
|
|
@@ -534,6 +560,7 @@ struct mg_context {
|
|
|
volatile int num_threads; // Number of threads
|
|
|
pthread_mutex_t mutex; // Protects (max|num)_threads
|
|
|
pthread_cond_t cond; // Condvar for tracking workers terminations
|
|
|
+ pthread_key_t pthreadTLS; /* Thread local storage index */
|
|
|
|
|
|
struct socket queue[MGSQLEN]; // Accepted sockets
|
|
|
volatile int sq_head; // Head of the socket queue
|
|
@@ -571,6 +598,13 @@ struct mg_connection {
|
|
|
pthread_mutex_t mutex; // Used by mg_lock/mg_unlock to ensure atomic transmissions for websockets
|
|
|
};
|
|
|
|
|
|
+struct mg_workerTLS {
|
|
|
+ int threadIndex;
|
|
|
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
|
|
|
+ HANDLE pthread_cond_helper_mutex;
|
|
|
+#endif
|
|
|
+};
|
|
|
+
|
|
|
// Directory entry
|
|
|
struct de {
|
|
|
struct mg_connection *conn;
|
|
@@ -5669,11 +5703,17 @@ static void *worker_thread_run(void *thread_func_param)
|
|
|
{
|
|
|
struct mg_context *ctx = (struct mg_context *) thread_func_param;
|
|
|
struct mg_connection *conn;
|
|
|
+ struct mg_workerTLS *tls;
|
|
|
|
|
|
+ tls = (struct mg_workerTLS *) calloc(1, sizeof(*tls));
|
|
|
conn = (struct mg_connection *) calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE);
|
|
|
- if (conn == NULL) {
|
|
|
+ if ((conn == NULL) || (tls == NULL)) {
|
|
|
mg_cry(fc(ctx), "%s", "Cannot create new connection struct, OOM");
|
|
|
} else {
|
|
|
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
|
|
|
+ tls->pthread_cond_helper_mutex = CreateMutex(NULL, FALSE, NULL);
|
|
|
+#endif
|
|
|
+ pthread_setspecific(ctx->pthreadTLS, tls);
|
|
|
conn->buf_size = MAX_REQUEST_SIZE;
|
|
|
conn->buf = (char *) (conn + 1);
|
|
|
conn->ctx = ctx;
|
|
@@ -5707,7 +5747,6 @@ static void *worker_thread_run(void *thread_func_param)
|
|
|
|
|
|
close_connection(conn);
|
|
|
}
|
|
|
- free(conn);
|
|
|
}
|
|
|
|
|
|
// Signal master that we're done with connection and exiting
|
|
@@ -5717,6 +5756,13 @@ static void *worker_thread_run(void *thread_func_param)
|
|
|
assert(ctx->num_threads >= 0);
|
|
|
(void) pthread_mutex_unlock(&ctx->mutex);
|
|
|
|
|
|
+ pthread_setspecific(ctx->pthreadTLS, 0);
|
|
|
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
|
|
|
+ CloseHandle(tls->pthread_cond_helper_mutex);
|
|
|
+#endif
|
|
|
+ free(tls);
|
|
|
+ free(conn);
|
|
|
+
|
|
|
DEBUG_TRACE(("exiting"));
|
|
|
return NULL;
|
|
|
}
|
|
@@ -5950,6 +5996,8 @@ static void free_context(struct mg_context *ctx)
|
|
|
free(ctx->workerthreadids);
|
|
|
}
|
|
|
|
|
|
+ pthread_key_delete(ctx->pthreadTLS);
|
|
|
+
|
|
|
// Deallocate context itself
|
|
|
free(ctx);
|
|
|
}
|
|
@@ -5991,6 +6039,12 @@ struct mg_context *mg_start(const struct mg_callbacks *callbacks,
|
|
|
if ((ctx = (struct mg_context *) calloc(1, sizeof(*ctx))) == NULL) {
|
|
|
return NULL;
|
|
|
}
|
|
|
+
|
|
|
+ if (0 != pthread_key_create(&ctx->pthreadTLS, NULL)) {
|
|
|
+ mg_cry(fc(ctx), "Cannot initialize thread local storage");
|
|
|
+ free(ctx); /* use free only here, and free_context afterwards */
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
ctx->callbacks = *callbacks;
|
|
|
ctx->user_data = user_data;
|
|
|
ctx->request_handlers = 0;
|