Skip to content

Commit ce21406

Browse files
committed
libvncserver: properly end listener thread on shutdown
... by using the self-pipe trick.
1 parent d138cf9 commit ce21406

File tree

2 files changed

+51
-9
lines changed

2 files changed

+51
-9
lines changed

libvncserver/main.c

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -619,21 +619,35 @@ listenerRun(void *data)
619619
socklen_t len;
620620
fd_set listen_fds; /* temp file descriptor list for select() */
621621

622-
/* TODO: this thread won't die by restarting the server */
623622
/* TODO: HTTP is not handled */
624-
while (1) {
623+
while (rfbIsActive(screen)) {
625624
client_fd = -1;
626625
FD_ZERO(&listen_fds);
627626
if(screen->listenSock != RFB_INVALID_SOCKET)
628627
FD_SET(screen->listenSock, &listen_fds);
629628
if(screen->listen6Sock != RFB_INVALID_SOCKET)
630629
FD_SET(screen->listen6Sock, &listen_fds);
630+
#ifndef WIN32
631+
FD_SET(screen->pipe_notify_listener_thread[0], &listen_fds);
632+
screen->maxFd = rfbMax(screen->maxFd, screen->pipe_notify_listener_thread[0]);
633+
#endif
631634

632635
if (select(screen->maxFd+1, &listen_fds, NULL, NULL, NULL) == -1) {
633636
rfbLogPerror("listenerRun: error in select");
634637
return THREAD_ROUTINE_RETURN_VALUE;
635638
}
636-
639+
640+
#ifndef WIN32
641+
if (FD_ISSET(screen->pipe_notify_listener_thread[0], &listen_fds))
642+
{
643+
/* Reset the pipe */
644+
char buf;
645+
while (read(screen->pipe_notify_listener_thread[0], &buf, sizeof(buf)) == sizeof(buf));
646+
/* Go on with loop */
647+
continue;
648+
}
649+
#endif
650+
637651
/* there is something on the listening sockets, handle new connections */
638652
len = sizeof (peer);
639653
if (FD_ISSET(screen->listenSock, &listen_fds))
@@ -921,6 +935,10 @@ rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
921935
screen->maxFd=0;
922936
screen->listenSock=RFB_INVALID_SOCKET;
923937
screen->listen6Sock=RFB_INVALID_SOCKET;
938+
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
939+
screen->pipe_notify_listener_thread[0] = -1;
940+
screen->pipe_notify_listener_thread[1] = -1;
941+
#endif
924942

925943
screen->fdQuota = 0.5;
926944

@@ -1180,6 +1198,21 @@ void rfbShutdownServer(rfbScreenInfoPtr screen,rfbBool disconnectClients) {
11801198

11811199
rfbHttpShutdownSockets(screen);
11821200
rfbShutdownSockets(screen);
1201+
1202+
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
1203+
if (screen->backgroundLoop) {
1204+
/*
1205+
Notify the listener thread. This simply writes a NULL byte to the notify pipe in order to get past the select()
1206+
in listenerRun, the loop in there will then break because the rfbShutdownSockets() above has set screen->socketState.
1207+
*/
1208+
write(screen->pipe_notify_listener_thread[1], "\x00", 1);
1209+
/* And wait for it to finish. */
1210+
pthread_join(screen->listener_thread, NULL);
1211+
/* Now we can close the pipe */
1212+
close(screen->pipe_notify_listener_thread[0]);
1213+
close(screen->pipe_notify_listener_thread[1]);
1214+
}
1215+
#endif
11831216
}
11841217

11851218
#if !defined LIBVNCSERVER_HAVE_GETTIMEOFDAY && defined WIN32
@@ -1287,15 +1320,19 @@ void rfbRunEventLoop(rfbScreenInfoPtr screen, long usec, rfbBool runInBackground
12871320
{
12881321
if(runInBackground) {
12891322
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
1290-
pthread_t listener_thread;
1291-
12921323
screen->backgroundLoop = TRUE;
1293-
1294-
pthread_create(&listener_thread, NULL, listenerRun, screen);
1324+
#ifndef WIN32
1325+
if (pipe(screen->pipe_notify_listener_thread) == -1) {
1326+
screen->pipe_notify_listener_thread[0] = -1;
1327+
screen->pipe_notify_listener_thread[1] = -1;
1328+
}
1329+
fcntl(screen->pipe_notify_listener_thread[0], F_SETFL, O_NONBLOCK);
1330+
#endif
1331+
pthread_create(&screen->listener_thread, NULL, listenerRun, screen);
12951332
return;
12961333
#elif defined(LIBVNCSERVER_HAVE_WIN32THREADS)
12971334
screen->backgroundLoop = TRUE;
1298-
_beginthread(listenerRun, 0, screen);
1335+
screen->listener_thread = _beginthread(listenerRun, 0, screen);
12991336
return;
13001337
#else
13011338
rfbErr("Can't run in background, because I don't have PThreads!\n");

rfb/rfb.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,12 @@ typedef struct _rfbScreenInfo
360360
of file descriptors LibVNCServer uses before denying new client connections.
361361
It is set to 0.5 per default. */
362362
float fdQuota;
363-
363+
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
364+
pthread_t listener_thread;
365+
int pipe_notify_listener_thread[2];
366+
#elif defined(LIBVNCSERVER_HAVE_WIN32THREADS)
367+
uintptr_t listener_thread;
368+
#endif
364369
} rfbScreenInfo, *rfbScreenInfoPtr;
365370

366371

0 commit comments

Comments
 (0)