From 62a21143be0010e6f9681394cfa9e93960169dcb Mon Sep 17 00:00:00 2001 From: Hugo Santos Date: Fri, 4 May 2007 18:43:30 +0000 Subject: [PATCH] fixed a race condition in TCP's WaitList Wait/Signal that was preventing Connect() from awake when it should. Reported by Francois Revol. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21024 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../network/protocols/tcp/TCPEndpoint.cpp | 20 +++++++++++++------ .../network/protocols/tcp/TCPEndpoint.h | 1 + 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp index be04b408e2..5da10c6070 100644 --- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp @@ -171,6 +171,7 @@ state_needs_finish(int32 state) WaitList::WaitList(const char *name) { + fCondition = 0; fSem = create_sem(0, name); } @@ -192,11 +193,17 @@ status_t WaitList::Wait(RecursiveLocker &locker, bigtime_t timeout, bool wakeNext) { locker.Unlock(); - status_t status = acquire_sem_etc(fSem, 1, B_ABSOLUTE_TIMEOUT - | B_CAN_INTERRUPT, timeout); + + status_t status = B_OK; + + while (status == B_OK && !atomic_test_and_set(&fCondition, 0, 1)) + status = acquire_sem_etc(fSem, 1, B_ABSOLUTE_TIMEOUT | B_CAN_INTERRUPT, + timeout); + locker.Lock(); - if (wakeNext && status == B_OK) + if (status == B_OK && wakeNext) Signal(); + return status; } @@ -204,8 +211,8 @@ WaitList::Wait(RecursiveLocker &locker, bigtime_t timeout, bool wakeNext) void WaitList::Signal() { - release_sem_etc(fSem, 1, B_DO_NOT_RESCHEDULE - | B_RELEASE_IF_WAITING_ONLY); + atomic_or(&fCondition, 1); + release_sem_etc(fSem, 1, B_DO_NOT_RESCHEDULE | B_RELEASE_IF_WAITING_ONLY); } @@ -418,7 +425,8 @@ TCPEndpoint::Connect(const sockaddr *address) } status = _WaitForEstablished(locker, absolute_timeout(timeout)); - TRACE(" Connect(): Connection complete: %s", strerror(status)); + TRACE(" Connect(): Connection complete: %s (timeout was %llu)", + strerror(status), timeout); return posix_error(status); } diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h index ddc1f43abf..a50fb68bf2 100644 --- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h +++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h @@ -36,6 +36,7 @@ public: void Signal(); private: + int32 fCondition; sem_id fSem; };