1
0
mirror of https://github.com/lammertb/libhttp.git synced 2026-01-27 08:02:47 +03:00
Files
libhttp/src/httplib_master_thread.c
2016-12-10 16:56:54 +01:00

171 lines
5.2 KiB
C

/*
* Copyright (c) 2016 Lammert Bies
* Copyright (c) 2013-2016 the Civetweb developers
* Copyright (c) 2004-2013 Sergey Lyubka
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libhttp-private.h"
static void master_thread_run( void *thread_func_param );
/*
* ... XX_httplib_master_thread( void *thread_func_param );
*
* The function XX_httplib_master_thread() runs the master thread of the
* webserver. Due to operating system differences there are two different
* function headers.
*/
#ifdef _WIN32
unsigned __stdcall XX_httplib_master_thread( void *thread_func_param ) {
#else
void *XX_httplib_master_thread( void *thread_func_param ) {
#endif
master_thread_run( thread_func_param );
return 0;
} /* XX_httplib_master_thread */
/*
* static void master_thread_run( void *thread_func_param );
*
* The function master_thread_run() does the heavy lifting to run the master
* thread of the LibHTTP webserver.
*/
static void master_thread_run(void *thread_func_param) {
struct mg_context *ctx = (struct mg_context *)thread_func_param;
struct mg_workerTLS tls;
struct pollfd *pfd;
unsigned int i;
unsigned int workerthreadcount;
if ( ctx == NULL ) return;
XX_httplib_set_thread_name( "master" );
/* Increase priority of the master thread */
#if defined(_WIN32)
SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL );
#elif defined(USE_MASTER_THREAD_PRIORITY)
int min_prio = sched_get_priority_min(SCHED_RR);
int max_prio = sched_get_priority_max(SCHED_RR);
if ((min_prio >= 0) && (max_prio >= 0)
&& ((USE_MASTER_THREAD_PRIORITY) <= max_prio)
&& ((USE_MASTER_THREAD_PRIORITY) >= min_prio)) {
struct sched_param sched_param = {0};
sched_param.sched_priority = (USE_MASTER_THREAD_PRIORITY);
pthread_setschedparam(pthread_self(), SCHED_RR, &sched_param);
}
#endif
/* Initialize thread local storage */
#if defined(_WIN32)
tls.pthread_cond_helper_mutex = CreateEvent(NULL, FALSE, FALSE, NULL);
#endif
tls.is_master = 1;
pthread_setspecific(XX_httplib_sTlsKey, &tls);
if (ctx->callbacks.init_thread) {
/* Callback for the master thread (type 0) */
ctx->callbacks.init_thread(ctx, 0);
}
/* Server starts *now* */
ctx->start_time = time( NULL );
/* Start the server */
pfd = ctx->listening_socket_fds;
while (ctx->stop_flag == 0) {
for (i = 0; i < ctx->num_listening_sockets; i++) {
pfd[i].fd = ctx->listening_sockets[i].sock;
pfd[i].events = POLLIN;
}
if (poll(pfd, ctx->num_listening_sockets, 200) > 0) {
for (i = 0; i < ctx->num_listening_sockets; i++) {
/* NOTE(lsm): on QNX, poll() returns POLLRDNORM after the
* successful poll, and POLLIN is defined as
* (POLLRDNORM | POLLRDBAND)
* Therefore, we're checking pfd[i].revents & POLLIN, not
* pfd[i].revents == POLLIN. */
if (ctx->stop_flag == 0 && (pfd[i].revents & POLLIN)) {
XX_httplib_accept_new_connection(&ctx->listening_sockets[i], ctx);
}
}
}
}
/* Here stop_flag is 1 - Initiate shutdown. */
/* Stop signal received: somebody called mg_stop. Quit. */
XX_httplib_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
pthread_cond_broadcast(&ctx->sq_full);
#endif
(void)pthread_mutex_unlock(&ctx->thread_mutex);
/* Join all worker threads to avoid leaking threads. */
workerthreadcount = ctx->cfg_worker_threads;
for (i = 0; i < workerthreadcount; i++) {
if (ctx->workerthreadids[i] != 0) {
XX_httplib_join_thread(ctx->workerthreadids[i]);
}
}
#if !defined(NO_SSL)
if (ctx->ssl_ctx != NULL) XX_httplib_uninitialize_ssl(ctx);
#endif
#if defined(_WIN32)
CloseHandle(tls.pthread_cond_helper_mutex);
#endif
pthread_setspecific(XX_httplib_sTlsKey, NULL);
/* Signal mg_stop() that we're done.
* WARNING: This must be the very last thing this
* thread does, as ctx becomes invalid after this line. */
ctx->stop_flag = 2;
} /* master_thread_run */