|  | @@ -79,6 +79,8 @@
 | 
											
												
													
														|  |  #include <stddef.h>
 |  |  #include <stddef.h>
 | 
											
												
													
														|  |  #include <stdio.h>
 |  |  #include <stdio.h>
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +#define MAX_WORKER_THREADS 1024
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |  #if defined(_WIN32) && !defined(__SYMBIAN32__) /* Windows specific */
 |  |  #if defined(_WIN32) && !defined(__SYMBIAN32__) /* Windows specific */
 | 
											
												
													
														|  |  #if defined(_MSC_VER) && _MSC_VER <= 1400
 |  |  #if defined(_MSC_VER) && _MSC_VER <= 1400
 | 
											
												
													
														|  |  #undef _WIN32_WINNT
 |  |  #undef _WIN32_WINNT
 | 
											
										
											
												
													
														|  | @@ -170,10 +172,23 @@ typedef long off_t;
 | 
											
												
													
														|  |  #endif /* !fileno MINGW #defines fileno */
 |  |  #endif /* !fileno MINGW #defines fileno */
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  typedef HANDLE pthread_mutex_t;
 |  |  typedef HANDLE pthread_mutex_t;
 | 
											
												
													
														|  | 
 |  | +typedef DWORD pthread_key_t;
 | 
											
												
													
														|  | 
 |  | +typedef HANDLE pthread_t;
 | 
											
												
													
														|  |  typedef struct {
 |  |  typedef struct {
 | 
											
												
													
														|  | -    HANDLE signal, broadcast;
 |  | 
 | 
											
												
													
														|  | 
 |  | +    CRITICAL_SECTION threadIdSec;
 | 
											
												
													
														|  | 
 |  | +    int waitingthreadcount;        /* The number of threads queued. */
 | 
											
												
													
														|  | 
 |  | +    pthread_t *waitingthreadhdls;  /* The thread handles. */
 | 
											
												
													
														|  |  } pthread_cond_t;
 |  |  } pthread_cond_t;
 | 
											
												
													
														|  | -typedef HANDLE pthread_t;
 |  | 
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +typedef DWORD clockid_t;
 | 
											
												
													
														|  | 
 |  | +#define CLOCK_MONOTONIC (1)
 | 
											
												
													
														|  | 
 |  | +#define CLOCK_REALTIME  (2)
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +struct timespec {
 | 
											
												
													
														|  | 
 |  | +    time_t   tv_sec;        /* seconds */
 | 
											
												
													
														|  | 
 |  | +    long     tv_nsec;       /* nanoseconds */
 | 
											
												
													
														|  | 
 |  | +};
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |  #define pid_t HANDLE /* MINGW typedefs pid_t to int. Using #define here. */
 |  |  #define pid_t HANDLE /* MINGW typedefs pid_t to int. Using #define here. */
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  static int pthread_mutex_lock(pthread_mutex_t *);
 |  |  static int pthread_mutex_lock(pthread_mutex_t *);
 | 
											
										
											
												
													
														|  | @@ -280,6 +295,31 @@ static DWORD pthread_self(void)
 | 
											
												
													
														|  |  {
 |  |  {
 | 
											
												
													
														|  |      return GetCurrentThreadId();
 |  |      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 */
 |  |  #endif /* _WIN32 */
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  #define MD5_STATIC static
 |  |  #define MD5_STATIC static
 | 
											
										
											
												
													
														|  | @@ -572,6 +612,16 @@ struct mg_connection {
 | 
											
												
													
														|  |                                     transmissions for websockets */
 |  |                                     transmissions for websockets */
 | 
											
												
													
														|  |  };
 |  |  };
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +static pthread_key_t sTlsKey;  /* Thread local storage index */
 | 
											
												
													
														|  | 
 |  | +static int sTlsInit = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +struct mg_workerTLS {
 | 
											
												
													
														|  | 
 |  | +    int is_master;
 | 
											
												
													
														|  | 
 |  | +#if defined(_WIN32) && !defined(__SYMBIAN32__)
 | 
											
												
													
														|  | 
 |  | +    HANDLE pthread_cond_helper_mutex;
 | 
											
												
													
														|  | 
 |  | +#endif
 | 
											
												
													
														|  | 
 |  | +};
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |  /* Directory entry */
 |  |  /* Directory entry */
 | 
											
												
													
														|  |  struct de {
 |  |  struct de {
 | 
											
												
													
														|  |      struct mg_connection *conn;
 |  |      struct mg_connection *conn;
 | 
											
										
											
												
													
														|  | @@ -1070,37 +1120,132 @@ static int pthread_mutex_unlock(pthread_mutex_t *mutex)
 | 
											
												
													
														|  |      return ReleaseMutex(*mutex) == 0 ? -1 : 0;
 |  |      return ReleaseMutex(*mutex) == 0 ? -1 : 0;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +static int clock_gettime(clockid_t clk_id, struct timespec *tp)
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +    FILETIME ft;
 | 
											
												
													
														|  | 
 |  | +    ULARGE_INTEGER li;
 | 
											
												
													
														|  | 
 |  | +    BOOL ok = FALSE;
 | 
											
												
													
														|  | 
 |  | +    double d;
 | 
											
												
													
														|  | 
 |  | +    static double perfcnt_per_sec = 0.0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    if (tp) {
 | 
											
												
													
														|  | 
 |  | +        if (clk_id == CLOCK_REALTIME) {
 | 
											
												
													
														|  | 
 |  | +            GetSystemTimeAsFileTime(&ft);
 | 
											
												
													
														|  | 
 |  | +            li.LowPart = ft.dwLowDateTime;
 | 
											
												
													
														|  | 
 |  | +            li.HighPart = ft.dwHighDateTime;
 | 
											
												
													
														|  | 
 |  | +            li.QuadPart -= 116444736000000000; /* 1.1.1970 in filedate */
 | 
											
												
													
														|  | 
 |  | +            tp->tv_sec = (time_t)(li.QuadPart / 10000000);
 | 
											
												
													
														|  | 
 |  | +            tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
 | 
											
												
													
														|  | 
 |  | +            ok = TRUE;
 | 
											
												
													
														|  | 
 |  | +        } else if (clk_id == CLOCK_MONOTONIC) {
 | 
											
												
													
														|  | 
 |  | +            if (perfcnt_per_sec==0) {
 | 
											
												
													
														|  | 
 |  | +                QueryPerformanceFrequency((LARGE_INTEGER *) &li);
 | 
											
												
													
														|  | 
 |  | +                perfcnt_per_sec = 1.0 / li.QuadPart;
 | 
											
												
													
														|  | 
 |  | +            }
 | 
											
												
													
														|  | 
 |  | +            if (perfcnt_per_sec!=0) {
 | 
											
												
													
														|  | 
 |  | +                QueryPerformanceCounter((LARGE_INTEGER *) &li);
 | 
											
												
													
														|  | 
 |  | +                d = li.QuadPart * perfcnt_per_sec;
 | 
											
												
													
														|  | 
 |  | +                tp->tv_sec = (time_t)d;
 | 
											
												
													
														|  | 
 |  | +                d -= tp->tv_sec;
 | 
											
												
													
														|  | 
 |  | +                tp->tv_nsec = (long)(d*1.0E9);
 | 
											
												
													
														|  | 
 |  | +                ok = TRUE;
 | 
											
												
													
														|  | 
 |  | +            }
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    return ok ? 0 : -1;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |  static int pthread_cond_init(pthread_cond_t *cv, const void *unused)
 |  |  static int pthread_cond_init(pthread_cond_t *cv, const void *unused)
 | 
											
												
													
														|  |  {
 |  |  {
 | 
											
												
													
														|  |      (void) unused;
 |  |      (void) unused;
 | 
											
												
													
														|  | -    cv->signal = CreateEvent(NULL, FALSE, FALSE, NULL);
 |  | 
 | 
											
												
													
														|  | -    cv->broadcast = CreateEvent(NULL, TRUE, FALSE, NULL);
 |  | 
 | 
											
												
													
														|  | -    return cv->signal != NULL && cv->broadcast != NULL ? 0 : -1;
 |  | 
 | 
											
												
													
														|  | 
 |  | +    InitializeCriticalSection(&cv->threadIdSec);
 | 
											
												
													
														|  | 
 |  | +    cv->waitingthreadcount = 0;
 | 
											
												
													
														|  | 
 |  | +    cv->waitingthreadhdls = calloc(MAX_WORKER_THREADS, sizeof(pthread_t));
 | 
											
												
													
														|  | 
 |  | +    return (cv->waitingthreadhdls!=NULL) ? 0 : -1;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static int pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mutex, const struct timespec * abstime)
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +    struct mg_workerTLS * tls = (struct mg_workerTLS *)TlsGetValue(sTlsKey);
 | 
											
												
													
														|  | 
 |  | +    int ok;
 | 
											
												
													
														|  | 
 |  | +    struct timespec tsnow;
 | 
											
												
													
														|  | 
 |  | +    int64_t nsnow, nswaitabs, nswaitrel;
 | 
											
												
													
														|  | 
 |  | +    DWORD mswaitrel;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    EnterCriticalSection(&cv->threadIdSec);
 | 
											
												
													
														|  | 
 |  | +    assert(cv->waitingthreadcount < MAX_WORKER_THREADS);
 | 
											
												
													
														|  | 
 |  | +    cv->waitingthreadhdls[cv->waitingthreadcount] = tls->pthread_cond_helper_mutex;
 | 
											
												
													
														|  | 
 |  | +    cv->waitingthreadcount++;
 | 
											
												
													
														|  | 
 |  | +    LeaveCriticalSection(&cv->threadIdSec);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    if (abstime) {
 | 
											
												
													
														|  | 
 |  | +        clock_gettime(CLOCK_REALTIME, &tsnow);
 | 
											
												
													
														|  | 
 |  | +        nsnow = (((uint64_t)tsnow.tv_sec)<<32) + tsnow.tv_nsec;
 | 
											
												
													
														|  | 
 |  | +        nswaitabs = (((uint64_t)abstime->tv_sec)<<32) + abstime->tv_nsec;
 | 
											
												
													
														|  | 
 |  | +        nswaitrel = nswaitabs - nsnow;
 | 
											
												
													
														|  | 
 |  | +        if (nswaitrel<0) nswaitrel=0;
 | 
											
												
													
														|  | 
 |  | +        mswaitrel = (DWORD)(nswaitrel / 1000000);
 | 
											
												
													
														|  | 
 |  | +    } else {
 | 
											
												
													
														|  | 
 |  | +        mswaitrel = INFINITE;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    pthread_mutex_unlock(mutex);
 | 
											
												
													
														|  | 
 |  | +    ok = (WAIT_OBJECT_0 == WaitForSingleObject(tls->pthread_cond_helper_mutex, mswaitrel));
 | 
											
												
													
														|  | 
 |  | +    pthread_mutex_lock(mutex);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    return ok ? 0 : -1;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  static int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex)
 |  |  static int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex)
 | 
											
												
													
														|  |  {
 |  |  {
 | 
											
												
													
														|  | -    HANDLE handles[] = {cv->signal, cv->broadcast};
 |  | 
 | 
											
												
													
														|  | -    ReleaseMutex(*mutex);
 |  | 
 | 
											
												
													
														|  | -    WaitForMultipleObjects(2, handles, FALSE, INFINITE);
 |  | 
 | 
											
												
													
														|  | -    return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
 |  | 
 | 
											
												
													
														|  | 
 |  | +    return pthread_cond_timedwait(cv, mutex, NULL);
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  static int pthread_cond_signal(pthread_cond_t *cv)
 |  |  static int pthread_cond_signal(pthread_cond_t *cv)
 | 
											
												
													
														|  |  {
 |  |  {
 | 
											
												
													
														|  | -    return SetEvent(cv->signal) == 0 ? -1 : 0;
 |  | 
 | 
											
												
													
														|  | 
 |  | +    int i;
 | 
											
												
													
														|  | 
 |  | +    HANDLE wkup = NULL;
 | 
											
												
													
														|  | 
 |  | +    BOOL ok = FALSE;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    EnterCriticalSection(&cv->threadIdSec);
 | 
											
												
													
														|  | 
 |  | +    if (cv->waitingthreadcount) {
 | 
											
												
													
														|  | 
 |  | +        wkup = cv->waitingthreadhdls[0];
 | 
											
												
													
														|  | 
 |  | +        ok = SetEvent(wkup);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        for (i=1; i<cv->waitingthreadcount; i++) {
 | 
											
												
													
														|  | 
 |  | +            cv->waitingthreadhdls[i-1] = cv->waitingthreadhdls[i];
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        cv->waitingthreadcount--;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        assert(ok);
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +    LeaveCriticalSection(&cv->threadIdSec);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    return ok ? 0 : 1;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  static int pthread_cond_broadcast(pthread_cond_t *cv)
 |  |  static int pthread_cond_broadcast(pthread_cond_t *cv)
 | 
											
												
													
														|  |  {
 |  |  {
 | 
											
												
													
														|  | -    /* Implementation with PulseEvent() has race condition, see
 |  | 
 | 
											
												
													
														|  | -       http://www.cs.wustl.edu/~schmidt/win32-cv-1.html */
 |  | 
 | 
											
												
													
														|  | -    return PulseEvent(cv->broadcast) == 0 ? -1 : 0;
 |  | 
 | 
											
												
													
														|  | 
 |  | +    EnterCriticalSection(&cv->threadIdSec);
 | 
											
												
													
														|  | 
 |  | +    while (cv->waitingthreadcount) {
 | 
											
												
													
														|  | 
 |  | +        pthread_cond_signal(cv);
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +    LeaveCriticalSection(&cv->threadIdSec);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    return 0;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  static int pthread_cond_destroy(pthread_cond_t *cv)
 |  |  static int pthread_cond_destroy(pthread_cond_t *cv)
 | 
											
												
													
														|  |  {
 |  |  {
 | 
											
												
													
														|  | -    return CloseHandle(cv->signal) && CloseHandle(cv->broadcast) ? 0 : -1;
 |  | 
 | 
											
												
													
														|  | 
 |  | +    EnterCriticalSection(&cv->threadIdSec);
 | 
											
												
													
														|  | 
 |  | +    assert(cv->waitingthreadcount==0);
 | 
											
												
													
														|  | 
 |  | +    cv->waitingthreadhdls = 0;
 | 
											
												
													
														|  | 
 |  | +    free(cv->waitingthreadhdls);
 | 
											
												
													
														|  | 
 |  | +    LeaveCriticalSection(&cv->threadIdSec);
 | 
											
												
													
														|  | 
 |  | +    DeleteCriticalSection(&cv->threadIdSec);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    return 0;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  /* For Windows, change all slashes to backslashes in path names. */
 |  |  /* For Windows, change all slashes to backslashes in path names. */
 | 
											
										
											
												
													
														|  | @@ -1370,7 +1515,12 @@ static void set_close_on_exec(SOCKET sock, struct mg_connection *conn /* may be
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  int mg_start_thread(mg_thread_func_t f, void *p)
 |  |  int mg_start_thread(mg_thread_func_t f, void *p)
 | 
											
												
													
														|  |  {
 |  |  {
 | 
											
												
													
														|  | 
 |  | +#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
 | 
											
												
													
														|  | 
 |  | +    /* Compile-time option to control stack size, e.g. -DUSE_STACK_SIZE=16384 */
 | 
											
												
													
														|  | 
 |  | +    return (long)_beginthread((void (__cdecl *)(void *)) f, USE_STACK_SIZE, p) == -1L ? -1 : 0;
 | 
											
												
													
														|  | 
 |  | +#else
 | 
											
												
													
														|  |      return (long)_beginthread((void (__cdecl *)(void *)) f, 0, p) == -1L ? -1 : 0;
 |  |      return (long)_beginthread((void (__cdecl *)(void *)) f, 0, p) == -1L ? -1 : 0;
 | 
											
												
													
														|  | 
 |  | +#endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  /* Start a thread storing the thread context. */
 |  |  /* Start a thread storing the thread context. */
 | 
											
										
											
												
													
														|  | @@ -1570,11 +1720,11 @@ int mg_start_thread(mg_thread_func_t func, void *param)
 | 
											
												
													
														|  |      (void) pthread_attr_init(&attr);
 |  |      (void) pthread_attr_init(&attr);
 | 
											
												
													
														|  |      (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 |  |      (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -#if defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1
 |  | 
 | 
											
												
													
														|  | 
 |  | +#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
 | 
											
												
													
														|  |      /* Compile-time option to control stack size,
 |  |      /* Compile-time option to control stack size,
 | 
											
												
													
														|  |         e.g. -DUSE_STACK_SIZE=16384 */
 |  |         e.g. -DUSE_STACK_SIZE=16384 */
 | 
											
												
													
														|  |      (void) pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
 |  |      (void) pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
 | 
											
												
													
														|  | -#endif /* defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1 */
 |  | 
 | 
											
												
													
														|  | 
 |  | +#endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      result = pthread_create(&thread_id, &attr, func, param);
 |  |      result = pthread_create(&thread_id, &attr, func, param);
 | 
											
												
													
														|  |      pthread_attr_destroy(&attr);
 |  |      pthread_attr_destroy(&attr);
 | 
											
										
											
												
													
														|  | @@ -1593,7 +1743,7 @@ static int mg_start_thread_with_id(mg_thread_func_t func, void *param,
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      (void) pthread_attr_init(&attr);
 |  |      (void) pthread_attr_init(&attr);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -#if defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1
 |  | 
 | 
											
												
													
														|  | 
 |  | +#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
 | 
											
												
													
														|  |      /* Compile-time option to control stack size,
 |  |      /* Compile-time option to control stack size,
 | 
											
												
													
														|  |         e.g. -DUSE_STACK_SIZE=16384 */
 |  |         e.g. -DUSE_STACK_SIZE=16384 */
 | 
											
												
													
														|  |      (void) pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
 |  |      (void) pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
 | 
											
										
											
												
													
														|  | @@ -5653,11 +5803,18 @@ static void *worker_thread_run(void *thread_func_param)
 | 
											
												
													
														|  |  {
 |  |  {
 | 
											
												
													
														|  |      struct mg_context *ctx = (struct mg_context *) thread_func_param;
 |  |      struct mg_context *ctx = (struct mg_context *) thread_func_param;
 | 
											
												
													
														|  |      struct mg_connection *conn;
 |  |      struct mg_connection *conn;
 | 
											
												
													
														|  | 
 |  | +    struct mg_workerTLS tls;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    tls.is_master = 0;
 | 
											
												
													
														|  | 
 |  | +#if defined(_WIN32) && !defined(__SYMBIAN32__)
 | 
											
												
													
														|  | 
 |  | +    tls.pthread_cond_helper_mutex = CreateEvent(NULL, FALSE, FALSE, NULL);
 | 
											
												
													
														|  | 
 |  | +#endif
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      conn = (struct mg_connection *) calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE);
 |  |      conn = (struct mg_connection *) calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE);
 | 
											
												
													
														|  |      if (conn == NULL) {
 |  |      if (conn == NULL) {
 | 
											
												
													
														|  |          mg_cry(fc(ctx), "%s", "Cannot create new connection struct, OOM");
 |  |          mg_cry(fc(ctx), "%s", "Cannot create new connection struct, OOM");
 | 
											
												
													
														|  |      } else {
 |  |      } else {
 | 
											
												
													
														|  | 
 |  | +        pthread_setspecific(sTlsKey, &tls);
 | 
											
												
													
														|  |          conn->buf_size = MAX_REQUEST_SIZE;
 |  |          conn->buf_size = MAX_REQUEST_SIZE;
 | 
											
												
													
														|  |          conn->buf = (char *) (conn + 1);
 |  |          conn->buf = (char *) (conn + 1);
 | 
											
												
													
														|  |          conn->ctx = ctx;
 |  |          conn->ctx = ctx;
 | 
											
										
											
												
													
														|  | @@ -5692,7 +5849,6 @@ static void *worker_thread_run(void *thread_func_param)
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |              close_connection(conn);
 |  |              close_connection(conn);
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  | -        free(conn);
 |  | 
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      /* Signal master that we're done with connection and exiting */
 |  |      /* Signal master that we're done with connection and exiting */
 | 
											
										
											
												
													
														|  | @@ -5702,6 +5858,12 @@ static void *worker_thread_run(void *thread_func_param)
 | 
											
												
													
														|  |      assert(ctx->num_threads >= 0);
 |  |      assert(ctx->num_threads >= 0);
 | 
											
												
													
														|  |      (void) pthread_mutex_unlock(&ctx->mutex);
 |  |      (void) pthread_mutex_unlock(&ctx->mutex);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +    pthread_setspecific(sTlsKey, 0);
 | 
											
												
													
														|  | 
 |  | +#if defined(_WIN32) && !defined(__SYMBIAN32__)
 | 
											
												
													
														|  | 
 |  | +    CloseHandle(tls.pthread_cond_helper_mutex);
 | 
											
												
													
														|  | 
 |  | +#endif
 | 
											
												
													
														|  | 
 |  | +    free(conn);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |      DEBUG_TRACE(("exiting"));
 |  |      DEBUG_TRACE(("exiting"));
 | 
											
												
													
														|  |      return NULL;
 |  |      return NULL;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
										
											
												
													
														|  | @@ -5800,6 +5962,7 @@ static void accept_new_connection(const struct socket *listener,
 | 
											
												
													
														|  |  static void master_thread_run(void *thread_func_param)
 |  |  static void master_thread_run(void *thread_func_param)
 | 
											
												
													
														|  |  {
 |  |  {
 | 
											
												
													
														|  |      struct mg_context *ctx = (struct mg_context *) thread_func_param;
 |  |      struct mg_context *ctx = (struct mg_context *) thread_func_param;
 | 
											
												
													
														|  | 
 |  | +    struct mg_workerTLS tls;
 | 
											
												
													
														|  |      struct pollfd *pfd;
 |  |      struct pollfd *pfd;
 | 
											
												
													
														|  |      int i;
 |  |      int i;
 | 
											
												
													
														|  |      int workerthreadcount;
 |  |      int workerthreadcount;
 | 
											
										
											
												
													
														|  | @@ -5820,6 +5983,12 @@ static void master_thread_run(void *thread_func_param)
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  #endif
 |  |  #endif
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +#if defined(_WIN32) && !defined(__SYMBIAN32__)
 | 
											
												
													
														|  | 
 |  | +    tls.pthread_cond_helper_mutex = CreateEvent(NULL, FALSE, FALSE, NULL);
 | 
											
												
													
														|  | 
 |  | +#endif
 | 
											
												
													
														|  | 
 |  | +    tls.is_master = 1;
 | 
											
												
													
														|  | 
 |  | +    pthread_setspecific(sTlsKey, &tls);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |      pfd = (struct pollfd *) calloc(ctx->num_listening_sockets, sizeof(pfd[0]));
 |  |      pfd = (struct pollfd *) calloc(ctx->num_listening_sockets, sizeof(pfd[0]));
 | 
											
												
													
														|  |      while (pfd != NULL && ctx->stop_flag == 0) {
 |  |      while (pfd != NULL && ctx->stop_flag == 0) {
 | 
											
												
													
														|  |          for (i = 0; i < ctx->num_listening_sockets; i++) {
 |  |          for (i = 0; i < ctx->num_listening_sockets; i++) {
 | 
											
										
											
												
													
														|  | @@ -5873,6 +6042,11 @@ static void master_thread_run(void *thread_func_param)
 | 
											
												
													
														|  |  #endif
 |  |  #endif
 | 
											
												
													
														|  |      DEBUG_TRACE(("exiting"));
 |  |      DEBUG_TRACE(("exiting"));
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +#if defined(_WIN32) && !defined(__SYMBIAN32__)
 | 
											
												
													
														|  | 
 |  | +    CloseHandle(tls.pthread_cond_helper_mutex);
 | 
											
												
													
														|  | 
 |  | +#endif
 | 
											
												
													
														|  | 
 |  | +    pthread_setspecific(sTlsKey, 0);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |      /* Signal mg_stop() that we're done.
 |  |      /* Signal mg_stop() that we're done.
 | 
											
												
													
														|  |         WARNING: This must be the very last thing this
 |  |         WARNING: This must be the very last thing this
 | 
											
												
													
														|  |         thread does, as ctx becomes invalid after this line. */
 |  |         thread does, as ctx becomes invalid after this line. */
 | 
											
										
											
												
													
														|  | @@ -5936,6 +6110,12 @@ static void free_context(struct mg_context *ctx)
 | 
											
												
													
														|  |          free(ctx->workerthreadids);
 |  |          free(ctx->workerthreadids);
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +    /* Deallocate the tls variable */
 | 
											
												
													
														|  | 
 |  | +    sTlsInit--;
 | 
											
												
													
														|  | 
 |  | +    if (sTlsInit==0) {
 | 
											
												
													
														|  | 
 |  | +        pthread_key_delete(sTlsKey);
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |      /* Deallocate context itself */
 |  |      /* Deallocate context itself */
 | 
											
												
													
														|  |      free(ctx);
 |  |      free(ctx);
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
										
											
												
													
														|  | @@ -5977,6 +6157,15 @@ struct mg_context *mg_start(const struct mg_callbacks *callbacks,
 | 
											
												
													
														|  |      if ((ctx = (struct mg_context *) calloc(1, sizeof(*ctx))) == NULL) {
 |  |      if ((ctx = (struct mg_context *) calloc(1, sizeof(*ctx))) == NULL) {
 | 
											
												
													
														|  |          return NULL;
 |  |          return NULL;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    if (sTlsInit==0) {
 | 
											
												
													
														|  | 
 |  | +        if (0 != pthread_key_create(&sTlsKey, NULL)) {
 | 
											
												
													
														|  | 
 |  | +            mg_cry(fc(ctx), "Cannot initialize thread local storage");
 | 
											
												
													
														|  | 
 |  | +            return NULL;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        sTlsInit++;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |      ctx->callbacks = *callbacks;
 |  |      ctx->callbacks = *callbacks;
 | 
											
												
													
														|  |      ctx->user_data = user_data;
 |  |      ctx->user_data = user_data;
 | 
											
												
													
														|  |      ctx->request_handlers = 0;
 |  |      ctx->request_handlers = 0;
 | 
											
										
											
												
													
														|  | @@ -6034,6 +6223,13 @@ struct mg_context *mg_start(const struct mg_callbacks *callbacks,
 | 
											
												
													
														|  |      (void) pthread_cond_init(&ctx->sq_full, NULL);
 |  |      (void) pthread_cond_init(&ctx->sq_full, NULL);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      workerthreadcount = atoi(ctx->config[NUM_THREADS]);
 |  |      workerthreadcount = atoi(ctx->config[NUM_THREADS]);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    if (workerthreadcount > MAX_WORKER_THREADS) {
 | 
											
												
													
														|  | 
 |  | +        mg_cry(fc(ctx), "Too many worker threads");
 | 
											
												
													
														|  | 
 |  | +        free_context(ctx);
 | 
											
												
													
														|  | 
 |  | +        return NULL;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |      if (workerthreadcount > 0) {
 |  |      if (workerthreadcount > 0) {
 | 
											
												
													
														|  |          ctx->workerthreadcount = workerthreadcount;
 |  |          ctx->workerthreadcount = workerthreadcount;
 | 
											
												
													
														|  |          ctx->workerthreadids = calloc(workerthreadcount, sizeof(pthread_t));
 |  |          ctx->workerthreadids = calloc(workerthreadcount, sizeof(pthread_t));
 |