• Christian Beier's avatar
    Fix deadlock in threaded mode when using nested rfbClientIteratorNext() calls. · 3df7537a
    Christian Beier authored
    Lengthy explanation follows...
    
    First, the scenario before this patch:
    
    We have three clients 1,2,3 connected. The main thread loops through
    them using rfbClientIteratorNext() (loop L1) and is currently at
    client 2 i.e. client 2's cl_2->refCount is 1. At this point we need to
    loop again through the clients, with cl_2->refCount == 1, i.e. do a
    loop L2 nested within loop L1.
    
    BUT: Now client 2 disconnects, it's clientInput thread terminates its
    clientOutput thread and calls rfbClientConnectionGone(). This LOCKs
    clientListMutex and WAITs for cl_2->refCount to become 0. This means
    this thread waits for the main thread to release cl_2. Waiting, with
    clientListMutex LOCKed!
    
    Meanwhile, the main thread is about to begin the inner
    rfbClientIteratorNext() loop L2. The first call to rfbClientIteratorNext()
    LOCKs clientListMutex. BAAM. This mutex is locked by cl2's clientInput
    thread and is only released when cl_2->refCount becomes 0. The main thread
    would decrement cl_2->refCount when it would continue with loop L1. But
    it's waiting for cl2's clientInput thread to release clientListMutex. Which
    never happens since this one's waiting for the main thread to decrement
    cl_2->refCount. DEADLOCK.
    
    Now, situation with this patch:
    
    Same as above, but when client 2 disconnects it's clientInput thread
    rfbClientConnectionGone(). This again LOCKs clientListMutex, removes cl_2
    from the linked list and UNLOCKS clientListMutex. The WAIT for
    cl_2->refCount to become 0 is _after_ that. Waiting, with
    clientListMutex UNLOCKed!
    
    Therefore, the main thread can continue, do the inner loop L2 (now only
    looping through 1,3 - 2 was removed from the linked list) and continue with
    loop L1, finally decrementing cl_2->refCount, allowing cl2's clientInput
    thread to continue and terminate. The resources held by cl2 are not free()'d
    by rfbClientConnectionGone until cl2->refCount becomes 0, i.e. loop L1 has
    released cl2.
    3df7537a
Name
Last commit
Last update
..
tightvnc-filetransfer Loading commit data...
Makefile.am Loading commit data...
auth.c Loading commit data...
cargs.c Loading commit data...
config.h Loading commit data...
corre.c Loading commit data...
cursor.c Loading commit data...
cutpaste.c Loading commit data...
draw.c Loading commit data...
font.c Loading commit data...
hextile.c Loading commit data...
httpd.c Loading commit data...
main.c Loading commit data...
private.h Loading commit data...
rfbconfig.h Loading commit data...
rfbcrypto.h Loading commit data...
rfbcrypto_gnutls.c Loading commit data...
rfbcrypto_included.c Loading commit data...
rfbcrypto_openssl.c Loading commit data...
rfbcrypto_polarssl.c Loading commit data...
rfbregion.c Loading commit data...
rfbserver.c Loading commit data...
rfbssl.h Loading commit data...
rfbssl_gnutls.c Loading commit data...
rfbssl_none.c Loading commit data...
rfbssl_openssl.c Loading commit data...
rre.c Loading commit data...
scale.c Loading commit data...
scale.h Loading commit data...
selbox.c Loading commit data...
sockets.c Loading commit data...
stats.c Loading commit data...
tableinit24.c Loading commit data...
tableinitcmtemplate.c Loading commit data...
tableinittctemplate.c Loading commit data...
tabletrans24template.c Loading commit data...
tabletranstemplate.c Loading commit data...
tight.c Loading commit data...
translate.c Loading commit data...
ultra.c Loading commit data...
websockets.c Loading commit data...
zlib.c Loading commit data...
zrle.c Loading commit data...
zrleencodetemplate.c Loading commit data...
zrleoutstream.c Loading commit data...
zrleoutstream.h Loading commit data...
zrlepalettehelper.c Loading commit data...
zrlepalettehelper.h Loading commit data...
zrletypes.h Loading commit data...