1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

Use ppoll to allow signals to wake service loop early on change of pollfd event

To enable this code you need to force LWS_HAS_PPOLL to de defined.

#defining it at the top of libwebsockets.c is enough.

Signed-off-by: Andy Green <andy.green@linaro.org>
This commit is contained in:
Andy Green 2013-12-25 16:34:37 +08:00
parent 91f19d8d79
commit 3b3fa9e208
4 changed files with 88 additions and 2 deletions

View file

@ -37,6 +37,8 @@
#include <netdb.h>
#endif
#include <sys/types.h>
#ifdef LWS_OPENSSL_SUPPORT
int openssl_websocket_private_data_index;
#endif
@ -83,6 +85,17 @@ static const char * const log_level_names[] = {
struct libwebsocket *wsi, struct pollfd *pollfd);
#endif
#ifdef LWS_HAS_PPOLL
/*
* set to the Thread ID that's doing the service loop just before entry to ppoll
* indicates service thread likely idling in ppoll()
* volatile because other threads may check it as part of processing for pollfd
* event change.
*/
static volatile int lws_idling_ppoll_tid;
#endif
/**
* lws_get_library_version: get version and git hash library built from
*
@ -1325,15 +1338,32 @@ libwebsocket_service(struct libwebsocket_context *context, int timeout_ms)
{
int n;
int m;
#ifdef LWS_HAS_PPOLL
struct timespec timeout_ts;
sigset_t sigmask;
#endif
/* stay dead once we are dead */
if (context == NULL)
return 1;
#ifdef LWS_HAS_PPOLL
lws_idling_ppoll_tid = context->protocols[0].callback(context, NULL,
LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
timeout_ts.tv_sec = timeout_ms / 1000;
timeout_ts.tv_nsec = timeout_ms % 1000;
sigemptyset(&sigmask);
sigaddset(&sigmask, SIGUSR2);
/* wait for something to need service */
n = ppoll(context->fds, context->fds_count, &timeout_ts, &sigmask);
lws_idling_ppoll_tid = 0;
#else
n = poll(context->fds, context->fds_count, timeout_ms);
#endif
if (n == 0) /* poll timeout */ {
libwebsocket_service_fd(context, NULL);
return 0;
@ -1408,13 +1438,19 @@ void
lws_change_pollfd(struct libwebsocket *wsi, int _and, int _or)
{
struct libwebsocket_context *context = wsi->protocol->owning_server;
int events;
#ifdef LWS_HAS_PPOLL
int tid;
int sampled_ppoll_tid;
#endif
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_LOCK_POLL,
wsi->user_space, (void *)(long)wsi->sock, 0);
context->fds[wsi->position_in_fds_table].events &= ~_and;
context->fds[wsi->position_in_fds_table].events |= _or;
events = context->fds[wsi->position_in_fds_table].events;
context->fds[wsi->position_in_fds_table].events = (events & ~_and) | _or;
/* external POLL support via protocol 0 */
if (_and)
@ -1427,6 +1463,26 @@ lws_change_pollfd(struct libwebsocket *wsi, int _and, int _or)
LWS_CALLBACK_SET_MODE_POLL_FD,
wsi->user_space, (void *)(long)wsi->sock, _or);
#ifdef LWS_HAS_PPOLL
/*
* if we changed something in this pollfd...
* ... and we're running in a different thread context
* than the service thread...
* ... and the service thread is waiting in ppoll()...
* then fire a SIGUSR2 at the service thread to force it to
* restart the ppoll() with our changed events
*/
if (events != context->fds[wsi->position_in_fds_table].events) {
sampled_ppoll_tid = lws_idling_ppoll_tid;
if (sampled_ppoll_tid) {
tid = context->protocols[0].callback(context, NULL,
LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
if (tid != sampled_ppoll_tid)
kill(sampled_ppoll_tid, SIGUSR2);
}
}
#endif
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_UNLOCK_POLL,
wsi->user_space, (void *)(long)wsi->sock, 0);
@ -1747,6 +1803,13 @@ int user_callback_handle_rxflow(callback_function callback_function,
return n;
}
/*
* This is just used to interrupt poll waiting
* we don't have to do anything with it.
*/
static void lws_sigusr2(int sig)
{
}
/**
* libwebsocket_create_context() - Create the websocket handler
@ -2036,6 +2099,8 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
goto bail;
}
signal(SIGUSR2, lws_sigusr2);
#ifdef SSL_OP_NO_COMPRESSION
SSL_CTX_set_options(context->ssl_ctx, SSL_OP_NO_COMPRESSION);
#endif
@ -2349,6 +2414,7 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
}
}
#endif
return context;
bail:

View file

@ -63,6 +63,9 @@ typedef SSIZE_T ssize_t;
#endif
#else // NOT WIN32
/* to get ppoll() */
#define __USE_GNU
#include <poll.h>
#include <unistd.h>
@ -169,6 +172,8 @@ enum libwebsocket_callback_reasons {
LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED,
LWS_CALLBACK_PROTOCOL_INIT,
LWS_CALLBACK_PROTOCOL_DESTROY,
LWS_CALLBACK_GET_THREAD_ID,
/* external poll() management support */
LWS_CALLBACK_ADD_POLL_FD,
LWS_CALLBACK_DEL_POLL_FD,

View file

@ -93,6 +93,8 @@
#include <netinet/tcp.h>
#include <arpa/inet.h>
/* to get ppoll() */
#define __USE_GNU
#include <poll.h>
#include <sys/mman.h>
#include <sys/time.h>

View file

@ -474,6 +474,19 @@ bail:
break;
#endif
case LWS_CALLBACK_GET_THREAD_ID:
/*
* if you will call "libwebsocket_callback_on_writable"
* from a different thread, return the caller thread ID
* here so lws can use this information to work out if it
* should signal the ppoll() loop to exit and restart early
* (only applies if the library has LWS_HAS_PPOLL
*/
/* return pthread_getthreadid_np(); */
break;
default:
break;
}