|  | @@ -773,9 +773,9 @@ struct mg_context {
 | 
	
		
			
				|  |  |      volatile int sq_tail;           /* Tail of the socket queue */
 | 
	
		
			
				|  |  |      pthread_cond_t sq_full;         /* Signaled when socket is produced */
 | 
	
		
			
				|  |  |      pthread_cond_t sq_empty;        /* Signaled when socket is consumed */
 | 
	
		
			
				|  |  | -    pthread_t masterthreadid;       /* The master thread ID. */
 | 
	
		
			
				|  |  | +    pthread_t masterthreadid;       /* The master thread ID */
 | 
	
		
			
				|  |  |      int workerthreadcount;          /* The amount of worker threads. */
 | 
	
		
			
				|  |  | -    pthread_t *workerthreadids;     /* The worker thread IDs. */
 | 
	
		
			
				|  |  | +    pthread_t *workerthreadids;     /* The worker thread IDs */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      unsigned long start_time;       /* Server start time, used for authentication */
 | 
	
		
			
				|  |  |      pthread_mutex_t nonce_mutex;    /* Protects nonce_count */
 | 
	
	
		
			
				|  | @@ -789,35 +789,35 @@ struct mg_context {
 | 
	
		
			
				|  |  |  #if defined(USE_LUA) && defined(USE_WEBSOCKET)
 | 
	
		
			
				|  |  |      /* linked list of shared lua websockets */
 | 
	
		
			
				|  |  |      struct mg_shared_lua_websocket_list *shared_lua_websockets;
 | 
	
		
			
				|  |  | +    pthread_t timerthreadid;        /* Time thread ID */
 | 
	
		
			
				|  |  | +    pthread_mutex_t timer_mutex;    /* Protects timer lists */
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  struct mg_connection {
 | 
	
		
			
				|  |  |      struct mg_request_info request_info;
 | 
	
		
			
				|  |  |      struct mg_context *ctx;
 | 
	
		
			
				|  |  | -    SSL *ssl;                   /* SSL descriptor */
 | 
	
		
			
				|  |  | -    SSL_CTX *client_ssl_ctx;    /* SSL context for client connections */
 | 
	
		
			
				|  |  | -    struct socket client;       /* Connected client */
 | 
	
		
			
				|  |  | -    time_t birth_time;          /* Time when request was received */
 | 
	
		
			
				|  |  | -    int64_t num_bytes_sent;     /* Total bytes sent to client */
 | 
	
		
			
				|  |  | -    int64_t content_len;        /* Content-Length header value */
 | 
	
		
			
				|  |  | -    int64_t consumed_content;   /* How many bytes of content have been read */
 | 
	
		
			
				|  |  | -    char *buf;                  /* Buffer for received data */
 | 
	
		
			
				|  |  | -    char *path_info;            /* PATH_INFO part of the URL */
 | 
	
		
			
				|  |  | -    int must_close;             /* 1 if connection must be closed */
 | 
	
		
			
				|  |  | -    int in_error_handler;       /* 1 if in handler for user defined error pages */
 | 
	
		
			
				|  |  | -    int buf_size;               /* Buffer size */
 | 
	
		
			
				|  |  | -    int request_len;            /* Size of the request + headers in a buffer */
 | 
	
		
			
				|  |  | -    int data_len;               /* Total size of data in a buffer */
 | 
	
		
			
				|  |  | -    int status_code;            /* HTTP reply status code, e.g. 200 */
 | 
	
		
			
				|  |  | -    int throttle;               /* Throttling, bytes/sec. <= 0 means no
 | 
	
		
			
				|  |  | -                                   throttle */
 | 
	
		
			
				|  |  | -    time_t last_throttle_time;  /* Last time throttled data was sent */
 | 
	
		
			
				|  |  | -    int64_t last_throttle_bytes;/* Bytes sent this second */
 | 
	
		
			
				|  |  | -    pthread_mutex_t mutex;      /* Used by mg_lock/mg_unlock to ensure atomic
 | 
	
		
			
				|  |  | -                                   transmissions for websockets */
 | 
	
		
			
				|  |  | +    SSL *ssl;                       /* SSL descriptor */
 | 
	
		
			
				|  |  | +    SSL_CTX *client_ssl_ctx;        /* SSL context for client connections */
 | 
	
		
			
				|  |  | +    struct socket client;           /* Connected client */
 | 
	
		
			
				|  |  | +    time_t birth_time;              /* Time when request was received */
 | 
	
		
			
				|  |  | +    int64_t num_bytes_sent;         /* Total bytes sent to client */
 | 
	
		
			
				|  |  | +    int64_t content_len;            /* Content-Length header value */
 | 
	
		
			
				|  |  | +    int64_t consumed_content;       /* How many bytes of content have been read */
 | 
	
		
			
				|  |  | +    char *buf;                      /* Buffer for received data */
 | 
	
		
			
				|  |  | +    char *path_info;                /* PATH_INFO part of the URL */
 | 
	
		
			
				|  |  | +    int must_close;                 /* 1 if connection must be closed */
 | 
	
		
			
				|  |  | +    int in_error_handler;           /* 1 if in handler for user defined error pages */
 | 
	
		
			
				|  |  | +    int buf_size;                   /* Buffer size */
 | 
	
		
			
				|  |  | +    int request_len;                /* Size of the request + headers in a buffer */
 | 
	
		
			
				|  |  | +    int data_len;                   /* Total size of data in a buffer */
 | 
	
		
			
				|  |  | +    int status_code;                /* HTTP reply status code, e.g. 200 */
 | 
	
		
			
				|  |  | +    int throttle;                   /* Throttling, bytes/sec. <= 0 means no throttle */
 | 
	
		
			
				|  |  | +    time_t last_throttle_time;      /* Last time throttled data was sent */
 | 
	
		
			
				|  |  | +    int64_t last_throttle_bytes;    /* Bytes sent this second */
 | 
	
		
			
				|  |  | +    pthread_mutex_t mutex;          /* Used by mg_lock/mg_unlock to ensure atomic transmissions for websockets */
 | 
	
		
			
				|  |  |  #if defined(USE_LUA) && defined(USE_WEBSOCKET)
 | 
	
		
			
				|  |  | -    void * lua_websocket_state; /* Lua_State for a websocket connection */
 | 
	
		
			
				|  |  | +    void * lua_websocket_state;     /* Lua_State for a websocket connection */
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1419,7 +1419,18 @@ static int pthread_mutex_destroy(pthread_mutex_t *mutex)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static int pthread_mutex_lock(pthread_mutex_t *mutex)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
 | 
	
		
			
				|  |  | +    return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0 ? 0 : -1;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int pthread_mutex_trylock(pthread_mutex_t *mutex)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    switch (WaitForSingleObject(*mutex, 0)) {
 | 
	
		
			
				|  |  | +        case WAIT_OBJECT_0:
 | 
	
		
			
				|  |  | +            return 0;
 | 
	
		
			
				|  |  | +        case WAIT_TIMEOUT:
 | 
	
		
			
				|  |  | +            return -2; /* EBUSY */
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return -1;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static int pthread_mutex_unlock(pthread_mutex_t *mutex)
 | 
	
	
		
			
				|  | @@ -6728,6 +6739,33 @@ static void *master_thread(void *thread_func_param)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  #endif /* _WIN32 */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#if defined(USE_LUA) && defined(USE_WEBSOCKET)
 | 
	
		
			
				|  |  | +void timer_thread_run(void *thread_func_param)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    struct mg_context *ctx = (struct mg_context *) thread_func_param;
 | 
	
		
			
				|  |  | +    while (ctx->stop_flag == 0) {
 | 
	
		
			
				|  |  | +        pthread_mutex_lock(&ctx->timer_mutex);
 | 
	
		
			
				|  |  | +        /* TODO: something useful */
 | 
	
		
			
				|  |  | +        pthread_mutex_unlock(&ctx->timer_mutex);
 | 
	
		
			
				|  |  | +        mg_sleep(1);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#ifdef _WIN32
 | 
	
		
			
				|  |  | +static unsigned __stdcall timer_thread(void *thread_func_param)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    timer_thread_run(thread_func_param);
 | 
	
		
			
				|  |  | +    return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  | +static void *timer_thread(void *thread_func_param)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    timer_thread_run(thread_func_param);
 | 
	
		
			
				|  |  | +    return NULL;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +#endif /* _WIN32 */
 | 
	
		
			
				|  |  | +#endif /* USE_LUA && USE_WEBSOCKET */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void free_context(struct mg_context *ctx)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      int i;
 | 
	
	
		
			
				|  | @@ -6745,6 +6783,10 @@ static void free_context(struct mg_context *ctx)
 | 
	
		
			
				|  |  |      /* Destroy other context global data structures mutex */
 | 
	
		
			
				|  |  |      (void) pthread_mutex_destroy(&ctx->nonce_mutex);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#if defined(USE_LUA) && defined(USE_WEBSOCKET)
 | 
	
		
			
				|  |  | +    (void) pthread_mutex_destroy(&ctx->timer_mutex);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      /* Deallocate config parameters */
 | 
	
		
			
				|  |  |      for (i = 0; i < NUM_OPTIONS; i++) {
 | 
	
		
			
				|  |  |          if (ctx->config[i] != NULL)
 | 
	
	
		
			
				|  | @@ -6937,6 +6979,10 @@ struct mg_context *mg_start(const struct mg_callbacks *callbacks,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      (void) pthread_mutex_init(&ctx->nonce_mutex, NULL);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#if defined(USE_LUA) && defined(USE_WEBSOCKET)
 | 
	
		
			
				|  |  | +    (void) pthread_mutex_init(&ctx->timer_mutex, NULL);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      workerthreadcount = atoi(ctx->config[NUM_THREADS]);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if (workerthreadcount > MAX_WORKER_THREADS) {
 | 
	
	
		
			
				|  | @@ -6955,6 +7001,11 @@ struct mg_context *mg_start(const struct mg_callbacks *callbacks,
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#if defined(USE_LUA) && defined(USE_WEBSOCKET)
 | 
	
		
			
				|  |  | +    /* Start timer thread */
 | 
	
		
			
				|  |  | +    mg_start_thread_with_id(timer_thread, ctx, &ctx->timerthreadid);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      /* Start master (listening) thread */
 | 
	
		
			
				|  |  |      mg_start_thread_with_id(master_thread, ctx, &ctx->masterthreadid);
 | 
	
		
			
				|  |  |  
 |