You are viewing a plain text version of this content. The canonical link for it is here.
Posted to bugs@apr.apache.org by bu...@apache.org on 2008/07/22 12:37:37 UTC
DO NOT REPLY [Bug 45455] New: rwlock sometimes allows a writer to
take the lock while a reader has the lock
https://issues.apache.org/bugzilla/show_bug.cgi?id=45455
Summary: rwlock sometimes allows a writer to take the lock while
a reader has the lock
Product: APR
Version: HEAD
Platform: PC
OS/Version: Windows Server 2003
Status: NEW
Severity: normal
Priority: P2
Component: APR
AssignedTo: bugs@apr.apache.org
ReportedBy: rbarkan@websense.com
Created an attachment (id=22298)
--> (https://issues.apache.org/bugzilla/attachment.cgi?id=22298)
A suggested fix and a test to verify
Take a look at the following lines from the apr_thread_rwlock_unlock()
(trunk/locks/win32/thread_rwlock.c):
...
146 : /* Nope, we must have a read lock */
147 : if (rwlock->readers &&
148 : ! InterlockedDecrement(&rwlock->readers) &&
149 : ! SetEvent(rwlock->read_event)) {
....
Notice that no mutex is taken during apr_thread_rwlock_unlock().
Now, consider a single reader is performing an unlock, called
InterlockedDecrement() on line 148, received 0 as a result of
InterlockedDecrement, and a context switch now happens right before the call to
SetEvent() in line 149.
Now, let's say that right after the context switch another thread tries to take
the read-lock. Here's the implementation of apr_thread_rwlock_rdlock_core():
...
65 : DWORD code = WaitForSingleObject(rwlock->write_mutex,
milliseconds);
66 :
67 : if (code == WAIT_FAILED || code == WAIT_TIMEOUT)
68 : return APR_FROM_OS_ERROR(code);
69 :
70 : /* We've successfully acquired the writer mutex, we
can't be locked
71 : * for write, so it's OK to add the reader lock. The
writer mutex
72 : * doubles as race condition protection for the readers
counter.
73 : */
74 : InterlockedIncrement(&rwlock->readers);
75 :
76 : if (! ResetEvent(rwlock->read_event))
77 : return apr_get_os_error();
78 :
79 : if (! ReleaseMutex(rwlock->write_mutex))
80 : return apr_get_os_error();
81 :
82 : return APR_SUCCESS;
...
After this thread is done taking the lock, the readers counter is equal to 1,
and the read_event is RESET.
Now, the system might context-switch back to the original thread doing an
unlock operation (at line 149) which will, unfortunately, SET the event.
If you've followed me so far, we've reached a situation where one thread has
the read-lock, the readers count is equal to 1 but the read_event is SET.
Now, if any thread will try to acquire a writer's lock, it will SUCCEED, and
not wait for the reader thread to release its reader-lock.
As you can see - this is a race between two readers, which allows a writer to
take the lock while a reader has it.
The comment in lines 71-72 is mesleading and isn't true.
As far as I can see, this issue was introduced 5 years ago, seen on revision
64541, and is part of all APR versions since 0.9.4.
Attached is my suggestion for a fix for this issue, as well as an addition to
the rwlock test which should cause the issue (if you're [un]lucky enough).
--
Configure bugmail: https://issues.apache.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: bugs-unsubscribe@apr.apache.org
For additional commands, e-mail: bugs-help@apr.apache.org