|  | @@ -2296,7 +2296,7 @@ struct socket {
 | 
	
		
			
				|  |  |  	unsigned char is_ssl;    /* Is port SSL-ed */
 | 
	
		
			
				|  |  |  	unsigned char ssl_redir; /* Is port supposed to redirect everything to SSL
 | 
	
		
			
				|  |  |  	                          * port */
 | 
	
		
			
				|  |  | -	unsigned char in_use;    /* Is valid */
 | 
	
		
			
				|  |  | +	unsigned char in_use;    /* 0: invalid, 1: valid, 2: free */
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2898,6 +2898,7 @@ event_destroy(void *eventhdl)
 | 
	
		
			
				|  |  |  struct posix_event {
 | 
	
		
			
				|  |  |  	pthread_mutex_t mutex;
 | 
	
		
			
				|  |  |  	pthread_cond_t cond;
 | 
	
		
			
				|  |  | +	int signaled;
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2920,6 +2921,7 @@ event_create(void)
 | 
	
		
			
				|  |  |  		mg_free(ret);
 | 
	
		
			
				|  |  |  		return 0;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | +	ret->signaled = 0;
 | 
	
		
			
				|  |  |  	return (void *)ret;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2929,7 +2931,10 @@ event_wait(void *eventhdl)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |  	struct posix_event *ev = (struct posix_event *)eventhdl;
 | 
	
		
			
				|  |  |  	pthread_mutex_lock(&(ev->mutex));
 | 
	
		
			
				|  |  | -	pthread_cond_wait(&(ev->cond), &(ev->mutex));
 | 
	
		
			
				|  |  | +	while (!ev->signaled) {
 | 
	
		
			
				|  |  | +		pthread_cond_wait(&(ev->cond), &(ev->mutex));
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	ev->signaled = 0;
 | 
	
		
			
				|  |  |  	pthread_mutex_unlock(&(ev->mutex));
 | 
	
		
			
				|  |  |  	return 1;
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -2941,6 +2946,7 @@ event_signal(void *eventhdl)
 | 
	
		
			
				|  |  |  	struct posix_event *ev = (struct posix_event *)eventhdl;
 | 
	
		
			
				|  |  |  	pthread_mutex_lock(&(ev->mutex));
 | 
	
		
			
				|  |  |  	pthread_cond_signal(&(ev->cond));
 | 
	
		
			
				|  |  | +	ev->signaled = 1;
 | 
	
		
			
				|  |  |  	pthread_mutex_unlock(&(ev->mutex));
 | 
	
		
			
				|  |  |  	return 1;
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -13435,7 +13441,7 @@ mg_set_websocket_handler_with_subprotocols(
 | 
	
		
			
				|  |  |  void
 | 
	
		
			
				|  |  |  mg_set_auth_handler(struct mg_context *ctx,
 | 
	
		
			
				|  |  |                      const char *uri,
 | 
	
		
			
				|  |  | -                    mg_request_handler handler,
 | 
	
		
			
				|  |  | +                    mg_authorization_handler handler,
 | 
	
		
			
				|  |  |                      void *cbdata)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |  	mg_set_handler_type(ctx,
 | 
	
	
		
			
				|  | @@ -17621,16 +17627,25 @@ produce_socket(struct mg_context *ctx, const struct socket *sp)
 | 
	
		
			
				|  |  |  	while (!ctx->stop_flag) {
 | 
	
		
			
				|  |  |  		for (i = 0; i < ctx->cfg_worker_threads; i++) {
 | 
	
		
			
				|  |  |  			/* find a free worker slot and signal it */
 | 
	
		
			
				|  |  | -			if (ctx->client_socks[i].in_use == 0) {
 | 
	
		
			
				|  |  | -				ctx->client_socks[i] = *sp;
 | 
	
		
			
				|  |  | -				ctx->client_socks[i].in_use = 1;
 | 
	
		
			
				|  |  | -				event_signal(ctx->client_wait_events[i]);
 | 
	
		
			
				|  |  | -				return;
 | 
	
		
			
				|  |  | +			if (ctx->client_socks[i].in_use == 2) {
 | 
	
		
			
				|  |  | +				(void)pthread_mutex_lock(&ctx->thread_mutex);
 | 
	
		
			
				|  |  | +				if ((ctx->client_socks[i].in_use == 2) && !ctx->stop_flag) {
 | 
	
		
			
				|  |  | +					ctx->client_socks[i] = *sp;
 | 
	
		
			
				|  |  | +					ctx->client_socks[i].in_use = 1;
 | 
	
		
			
				|  |  | +					/* socket has been moved to the consumer */
 | 
	
		
			
				|  |  | +					(void)pthread_mutex_unlock(&ctx->thread_mutex);
 | 
	
		
			
				|  |  | +					(void)event_signal(ctx->client_wait_events[i]);
 | 
	
		
			
				|  |  | +					return;
 | 
	
		
			
				|  |  | +				}
 | 
	
		
			
				|  |  | +				(void)pthread_mutex_unlock(&ctx->thread_mutex);
 | 
	
		
			
				|  |  |  			}
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  		/* queue is full */
 | 
	
		
			
				|  |  |  		mg_sleep(1);
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | +	/* must consume */
 | 
	
		
			
				|  |  | +	set_blocking_mode(sp->sock);
 | 
	
		
			
				|  |  | +	closesocket(sp->sock);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -17638,12 +17653,31 @@ static int
 | 
	
		
			
				|  |  |  consume_socket(struct mg_context *ctx, struct socket *sp, int thread_index)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |  	DEBUG_TRACE("%s", "going idle");
 | 
	
		
			
				|  |  | -	ctx->client_socks[thread_index].in_use = 0;
 | 
	
		
			
				|  |  | +	(void)pthread_mutex_lock(&ctx->thread_mutex);
 | 
	
		
			
				|  |  | +	ctx->client_socks[thread_index].in_use = 2;
 | 
	
		
			
				|  |  | +	(void)pthread_mutex_unlock(&ctx->thread_mutex);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	event_wait(ctx->client_wait_events[thread_index]);
 | 
	
		
			
				|  |  | -	*sp = ctx->client_socks[thread_index];
 | 
	
		
			
				|  |  | -	DEBUG_TRACE("grabbed socket %d, going busy", sp ? sp->sock : -1);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	return !ctx->stop_flag;
 | 
	
		
			
				|  |  | +	(void)pthread_mutex_lock(&ctx->thread_mutex);
 | 
	
		
			
				|  |  | +	*sp = ctx->client_socks[thread_index];
 | 
	
		
			
				|  |  | +	if (ctx->stop_flag) {
 | 
	
		
			
				|  |  | +		(void)pthread_mutex_unlock(&ctx->thread_mutex);
 | 
	
		
			
				|  |  | +		if (sp->in_use == 1) {
 | 
	
		
			
				|  |  | +			/* must consume */
 | 
	
		
			
				|  |  | +			set_blocking_mode(sp->sock);
 | 
	
		
			
				|  |  | +			closesocket(sp->sock);
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		return 0;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	(void)pthread_mutex_unlock(&ctx->thread_mutex);
 | 
	
		
			
				|  |  | +	if (sp->in_use == 1) {
 | 
	
		
			
				|  |  | +		DEBUG_TRACE("grabbed socket %d, going busy", sp->sock);
 | 
	
		
			
				|  |  | +		return 1;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	/* must not reach here */
 | 
	
		
			
				|  |  | +	DEBUG_ASSERT(0);
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #else /* ALTERNATIVE_QUEUE */
 | 
	
	
		
			
				|  | @@ -17791,15 +17825,10 @@ worker_thread_run(struct worker_thread_args *thread_args)
 | 
	
		
			
				|  |  |  	conn->conn_state = 1; /* not consumed */
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#if defined(ALTERNATIVE_QUEUE)
 | 
	
		
			
				|  |  | -	while ((ctx->stop_flag == 0)
 | 
	
		
			
				|  |  | -	       && consume_socket(ctx, &conn->client, conn->thread_index)) {
 | 
	
		
			
				|  |  | -#else
 | 
	
		
			
				|  |  |  	/* Call consume_socket() even when ctx->stop_flag > 0, to let it
 | 
	
		
			
				|  |  |  	 * signal sq_empty condvar to wake up the master waiting in
 | 
	
		
			
				|  |  |  	 * produce_socket() */
 | 
	
		
			
				|  |  |  	while (consume_socket(ctx, &conn->client, conn->thread_index)) {
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		conn->conn_birth_time = time(NULL);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -18083,20 +18112,15 @@ master_thread_run(void *thread_func_param)
 | 
	
		
			
				|  |  |  	close_all_listening_sockets(ctx);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	/* Wakeup workers that are waiting for connections to handle. */
 | 
	
		
			
				|  |  | -	(void)pthread_mutex_lock(&ctx->thread_mutex);
 | 
	
		
			
				|  |  |  #if defined(ALTERNATIVE_QUEUE)
 | 
	
		
			
				|  |  |  	for (i = 0; i < ctx->cfg_worker_threads; i++) {
 | 
	
		
			
				|  |  |  		event_signal(ctx->client_wait_events[i]);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		/* Since we know all sockets, we can shutdown the connections. */
 | 
	
		
			
				|  |  | -		if (ctx->client_socks[i].in_use) {
 | 
	
		
			
				|  |  | -			shutdown(ctx->client_socks[i].sock, SHUTDOWN_BOTH);
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  #else
 | 
	
		
			
				|  |  | +	(void)pthread_mutex_lock(&ctx->thread_mutex);
 | 
	
		
			
				|  |  |  	pthread_cond_broadcast(&ctx->sq_full);
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  |  	(void)pthread_mutex_unlock(&ctx->thread_mutex);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	/* Join all worker threads to avoid leaking threads. */
 | 
	
		
			
				|  |  |  	workerthreadcount = ctx->cfg_worker_threads;
 |