mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
Add libwebsocket_cancel_service() to let a pending libwebsocket_service() return
Use poll() with a pipe instead of ppoll() to allow the stop polling on all UNIX platforms.
This commit is contained in:
parent
25f8b9e230
commit
1ee57f6fe8
4 changed files with 75 additions and 52 deletions
|
@ -90,16 +90,6 @@ static const char * const log_level_names[] = {
|
|||
#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
|
||||
*
|
||||
|
@ -1276,6 +1266,8 @@ libwebsocket_context_destroy(struct libwebsocket_context *context)
|
|||
for (n = 0; n < context->fds_count; n++) {
|
||||
struct libwebsocket *wsi =
|
||||
context->lws_lookup[context->fds[n].fd];
|
||||
if (!wsi)
|
||||
continue;
|
||||
libwebsocket_close_and_free_session(context,
|
||||
wsi, LWS_CLOSE_STATUS_NOSTATUS /* no protocol close */);
|
||||
n--;
|
||||
|
@ -1313,6 +1305,8 @@ libwebsocket_context_destroy(struct libwebsocket_context *context)
|
|||
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
#else
|
||||
close(context->dummy_pipe_fds[0]);
|
||||
close(context->dummy_pipe_fds[1]);
|
||||
close(context->fd_random);
|
||||
#endif
|
||||
|
||||
|
@ -1392,33 +1386,18 @@ 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
|
||||
char buf;
|
||||
|
||||
/* 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,
|
||||
context->service_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;
|
||||
|
||||
sigprocmask(SIG_BLOCK, NULL, &sigmask);
|
||||
sigdelset(&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
|
||||
context->service_tid = 0;
|
||||
|
||||
if (n == 0) /* poll timeout */ {
|
||||
libwebsocket_service_fd(context, NULL);
|
||||
return 0;
|
||||
|
@ -1436,6 +1415,13 @@ libwebsocket_service(struct libwebsocket_context *context, int timeout_ms)
|
|||
for (n = 0; n < context->fds_count; n++) {
|
||||
if (!context->fds[n].revents)
|
||||
continue;
|
||||
#ifndef _WIN32
|
||||
if (context->fds[n].fd == context->dummy_pipe_fds[0]) {
|
||||
if (read(context->fds[n].fd, &buf, 1) != 1)
|
||||
lwsl_err("Cannot read from dummy pipe.");
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
m = libwebsocket_service_fd(context, &context->fds[n]);
|
||||
if (m < 0)
|
||||
return -1;
|
||||
|
@ -1447,6 +1433,25 @@ libwebsocket_service(struct libwebsocket_context *context, int timeout_ms)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* libwebsocket_cancel_service() - Cancel servicing of pending websocket activity
|
||||
* @context: Websocket context
|
||||
*
|
||||
* This function let a call to libwebsocket_service() waiting for a timeout
|
||||
* immediately return.
|
||||
*
|
||||
* At the moment this functionality cannot be used on Windows.
|
||||
*/
|
||||
LWS_VISIBLE void
|
||||
libwebsocket_cancel_service(struct libwebsocket_context *context)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
char buf = 0;
|
||||
if (write(context->dummy_pipe_fds[1], &buf, sizeof(buf)) != 1)
|
||||
lwsl_err("Cannot write to dummy pipe.");
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
int
|
||||
lws_any_extension_handled(struct libwebsocket_context *context,
|
||||
|
@ -1498,10 +1503,8 @@ 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
|
||||
int sampled_tid;
|
||||
struct libwebsocket_pollargs pa;
|
||||
|
||||
pa.fd = wsi->sock;
|
||||
|
@ -1518,26 +1521,22 @@ lws_change_pollfd(struct libwebsocket *wsi, int _and, int _or)
|
|||
LWS_CALLBACK_CHANGE_MODE_POLL_FD,
|
||||
wsi->user_space, (void *) &pa, 0);
|
||||
|
||||
|
||||
#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
|
||||
* ... and the service thread is waiting ...
|
||||
* then cancel it to force a restart 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) {
|
||||
sampled_tid = context->service_tid;
|
||||
if (sampled_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);
|
||||
if (tid != sampled_tid)
|
||||
libwebsocket_cancel_service(context);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
context->protocols[0].callback(context, wsi,
|
||||
LWS_CALLBACK_UNLOCK_POLL,
|
||||
|
@ -2049,7 +2048,24 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
|
|||
memset(context->lws_lookup, 0, sizeof(struct libwebsocket *) *
|
||||
context->max_fds);
|
||||
|
||||
#ifdef _WIN32
|
||||
context->fds_count = 0;
|
||||
#else
|
||||
if (pipe(context->dummy_pipe_fds)) {
|
||||
lwsl_err("Unable to create pipe\n");
|
||||
free(context->lws_lookup);
|
||||
free(context->fds);
|
||||
free(context);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* use the read end of pipe as first item */
|
||||
context->fds[0].fd = context->dummy_pipe_fds[0];
|
||||
context->fds[0].events = POLLIN;
|
||||
context->fds[0].revents = 0;
|
||||
context->fds_count = 1;
|
||||
#endif
|
||||
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
context->extensions = info->extensions;
|
||||
#endif
|
||||
|
|
|
@ -69,10 +69,6 @@ typedef SSIZE_T ssize_t;
|
|||
|
||||
#else // NOT WIN32
|
||||
|
||||
/* to get ppoll() */
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
@ -969,6 +965,9 @@ libwebsocket_context_destroy(struct libwebsocket_context *context);
|
|||
LWS_VISIBLE LWS_EXTERN int
|
||||
libwebsocket_service(struct libwebsocket_context *context, int timeout_ms);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
libwebsocket_cancel_service(struct libwebsocket_context *context);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
libwebsocket_service_fd(struct libwebsocket_context *context,
|
||||
struct pollfd *pollfd);
|
||||
|
|
|
@ -91,9 +91,6 @@
|
|||
#include <netinet/in.h>
|
||||
#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>
|
||||
|
@ -296,6 +293,17 @@ struct libwebsocket_context {
|
|||
int listen_service_fd;
|
||||
int listen_service_extraseen;
|
||||
|
||||
/*
|
||||
* set to the Thread ID that's doing the service loop just before entry
|
||||
* to poll indicates service thread likely idling in poll()
|
||||
* volatile because other threads may check it as part of processing
|
||||
* for pollfd event change.
|
||||
*/
|
||||
volatile int service_tid;
|
||||
#ifndef _WIN32
|
||||
int dummy_pipe_fds[2];
|
||||
#endif
|
||||
|
||||
int ka_time;
|
||||
int ka_probes;
|
||||
int ka_interval;
|
||||
|
|
|
@ -59,6 +59,7 @@ struct pollfd *pollfds;
|
|||
int *fd_lookup;
|
||||
int count_pollfds;
|
||||
static volatile int force_exit = 0;
|
||||
static struct libwebsocket_context *context;
|
||||
|
||||
/*
|
||||
* This demo server shows how to use libwebsockets for one or more
|
||||
|
@ -476,8 +477,7 @@ bail:
|
|||
* 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
|
||||
* should signal the poll() loop to exit and restart early
|
||||
*/
|
||||
|
||||
/* return pthread_getthreadid_np(); */
|
||||
|
@ -732,6 +732,7 @@ static struct libwebsocket_protocols protocols[] = {
|
|||
void sighandler(int sig)
|
||||
{
|
||||
force_exit = 1;
|
||||
libwebsocket_cancel_service(context);
|
||||
}
|
||||
|
||||
static struct option options[] = {
|
||||
|
@ -755,7 +756,6 @@ int main(int argc, char **argv)
|
|||
char key_path[1024];
|
||||
int n = 0;
|
||||
int use_ssl = 0;
|
||||
struct libwebsocket_context *context;
|
||||
int opts = 0;
|
||||
char interface_name[128] = "";
|
||||
const char *iface = NULL;
|
||||
|
|
Loading…
Add table
Reference in a new issue