Skip to content

Commit b9bc09b

Browse files
committed
Revert "libvncserver: indicate client thread end by other means than socket"
This reverts commit 336fc84. Waiting for the client-to-server thread to finish in rfbCloseClient() caused deadlocks in production environments. Revert the patch and redo in a little bit less intrusive way.
1 parent 336fc84 commit b9bc09b

3 files changed

Lines changed: 23 additions & 52 deletions

File tree

libvncserver/main.c

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ clientOutput(void *data)
461461
while (1) {
462462
haveUpdate = false;
463463
while (!haveUpdate) {
464-
if (cl->sock == RFB_INVALID_SOCKET || cl->state == RFB_SHUTDOWN) {
464+
if (cl->sock == RFB_INVALID_SOCKET) {
465465
/* Client has disconnected. */
466466
return THREAD_ROUTINE_RETURN_VALUE;
467467
}
@@ -528,7 +528,7 @@ clientInput(void *data)
528528
uintptr_t output_thread = _beginthread(clientOutput, 0, cl);
529529
#endif
530530

531-
while (cl->state != RFB_SHUTDOWN) {
531+
while (1) {
532532
fd_set rfds, wfds, efds;
533533
struct timeval tv;
534534
int n;
@@ -604,10 +604,6 @@ clientInput(void *data)
604604
UNLOCK(cl->updateMutex);
605605
THREAD_JOIN(output_thread);
606606

607-
/* Close client sock */
608-
rfbCloseSocket(cl->sock);
609-
cl->sock = RFB_INVALID_SOCKET;
610-
611607
rfbClientConnectionGone(cl);
612608

613609
return THREAD_ROUTINE_RETURN_VALUE;
@@ -624,16 +620,8 @@ listenerRun(void *data)
624620
socklen_t len;
625621
fd_set listen_fds; /* temp file descriptor list for select() */
626622

627-
/*
628-
Only checking socket state here and not using rfbIsActive()
629-
because: When rfbShutdownServer() is called by the client, it runs in
630-
the client-to-server thread's context, resulting in itself calling
631-
its own the pthread_join(), returning immediately, leaving the
632-
client-to-server thread to actually terminate _after_ the listener thread
633-
is terminated, leaving the client list still populated.
634-
*/
635623
/* TODO: HTTP is not handled */
636-
while (screen->socketState != RFB_SOCKET_SHUTDOWN) {
624+
while (rfbIsActive(screen)) {
637625
client_fd = -1;
638626
FD_ZERO(&listen_fds);
639627
if(screen->listenSock != RFB_INVALID_SOCKET)
@@ -1185,14 +1173,22 @@ void rfbShutdownServer(rfbScreenInfoPtr screen,rfbBool disconnectClients) {
11851173
rfbCloseClient(currentCl);
11861174
}
11871175

1176+
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
1177+
if(currentCl->screen->backgroundLoop) {
11881178
/*
1189-
In threaded mode, rfbClientConnectionGone() is called by the client-to-server thread.
1190-
Only need to call this here for non-threaded mode.
1191-
*/
1192-
#if defined(LIBVNCSERVER_HAVE_LIBPTHREAD) || defined(LIBVNCSERVER_HAVE_WIN32THREADS)
1193-
if(!currentCl->screen->backgroundLoop)
1179+
Notify the thread. This simply writes a NULL byte to the notify pipe in order to get past the select()
1180+
in clientInput(), the loop in there will then break because the rfbCloseClient() above has set
1181+
currentCl->sock to -1.
1182+
*/
1183+
write(currentCl->pipe_notify_client_thread[1], "\x00", 1);
1184+
/* And wait for it to finish. */
1185+
pthread_join(currentCl->client_thread, NULL);
1186+
} else {
1187+
rfbClientConnectionGone(currentCl);
1188+
}
1189+
#else
1190+
rfbClientConnectionGone(currentCl);
11941191
#endif
1195-
rfbClientConnectionGone(currentCl);
11961192

11971193
currentCl = nextCl;
11981194
}
@@ -1204,7 +1200,6 @@ void rfbShutdownServer(rfbScreenInfoPtr screen,rfbBool disconnectClients) {
12041200
rfbShutdownSockets(screen);
12051201

12061202
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
1207-
screen->socketState = RFB_SOCKET_SHUTDOWN; /* Set this so the listener thread ends */
12081203
if (screen->backgroundLoop) {
12091204
/*
12101205
Notify the listener thread. This simply writes a NULL byte to the notify pipe in order to get past the select()

libvncserver/sockets.c

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -556,47 +556,24 @@ rfbCloseClient(rfbClientPtr cl)
556556
if (cl->sock != RFB_INVALID_SOCKET)
557557
#endif
558558
{
559-
/* Remove client sock from allFds and adapt maxFd */
560559
FD_CLR(cl->sock,&(cl->screen->allFds));
561560
if(cl->sock==cl->screen->maxFd)
562561
while(cl->screen->maxFd>0
563562
&& !FD_ISSET(cl->screen->maxFd,&(cl->screen->allFds)))
564563
cl->screen->maxFd--;
565564
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
566-
/* Has to happen before socket close as the SSL implementation might send a goodbye */
567565
if (cl->sslctx)
568566
rfbssl_destroy(cl);
569567
free(cl->wspath);
570568
#endif
569+
#ifndef __MINGW32__
570+
shutdown(cl->sock,SHUT_RDWR);
571+
#endif
572+
rfbCloseSocket(cl->sock);
573+
cl->sock = RFB_INVALID_SOCKET;
571574
}
572575
TSIGNAL(cl->updateCond);
573576
UNLOCK(cl->updateMutex);
574-
575-
/*
576-
Client socket closing, either via the client-to-server thread or directly.
577-
*/
578-
#if defined(LIBVNCSERVER_HAVE_LIBPTHREAD) || defined(LIBVNCSERVER_HAVE_WIN32THREADS)
579-
if(cl->screen->backgroundLoop) {
580-
/* Indicate to client-to-server thread that it should not go on */
581-
cl->state = RFB_SHUTDOWN;
582-
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
583-
/*
584-
Notify the thread. This simply writes a NULL byte to the notify pipe in order to get past the select()
585-
in clientInput(), the loop in there will then break because the client state has been set to
586-
RFB_SHUTDOWN. Client socket closing will be done by the thread.
587-
*/
588-
write(cl->pipe_notify_client_thread[1], "\x00", 1);
589-
/* And wait for it to finish. */
590-
pthread_join(cl->client_thread, NULL);
591-
#endif
592-
} else
593-
#endif
594-
/* Either no threading support or threading support with screen->backgroundloop == false */
595-
{
596-
/* Close client sock */
597-
rfbCloseSocket(cl->sock);
598-
cl->sock = RFB_INVALID_SOCKET;
599-
}
600577
}
601578

602579

rfb/rfb.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -491,8 +491,7 @@ typedef struct _rfbClientRec {
491491
/* Ephemeral internal-use states that will never be seen by software
492492
* using LibVNCServer to provide services: */
493493

494-
RFB_INITIALISATION_SHARED, /**< sending initialisation messages with implicit shared-flag already true */
495-
RFB_SHUTDOWN /**< shutting down */
494+
RFB_INITIALISATION_SHARED /**< sending initialisation messages with implicit shared-flag already true */
496495
} state;
497496

498497
rfbBool reverseConnection;

0 commit comments

Comments
 (0)