فهرست منبع

provide pthread specific (thread local storage) functions

bel 11 سال پیش
والد
کامیت
1c88ec6687
1فایلهای تغییر یافته به همراه56 افزوده شده و 2 حذف شده
  1. 56 2
      src/civetweb.c

+ 56 - 2
src/civetweb.c

@@ -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;