You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@apr.apache.org by Christian Gross <Ch...@yahoo.de> on 2001/04/29 01:16:36 UTC
[PATCH] Read Write Locks for Windows Platform
Here is an implementation of Windows based Reader Writer locks.
I tested them a bit and they passed that. However these changes
should be looked at.
Christian
===================================================================
--- c:\projects\apr\include\apr_errno.h Sun Apr 8 06:19:36 2001
+++ c:\apr\include\apr_errno.h Sat Apr 28 17:22:56 2001
@@ -248,7 +248,7 @@
#define APR_EINCOMPLETE (APR_OS_START_ERROR + 22)
#define APR_EABOVEROOT (APR_OS_START_ERROR + 23)
#define APR_EBADPATH (APR_OS_START_ERROR + 24)
-
+#define APR_ELOCKTYPE (APR_OS_START_ERROR + 25)
/* APR ERROR VALUE TESTS */
#define APR_STATUS_IS_ENOSTAT(s) ((s) == APR_ENOSTAT)
--- c:\projects\apr\include\apr_lock.h Thu Feb 15 23:41:18 2001
+++ c:\apr\include\apr_lock.h Sat Apr 28 16:35:47 2001
@@ -103,13 +103,23 @@
apr_lockscope_e scope,
const char *fname,
apr_pool_t *cont);
-
/**
* Lock a protected region.
* @param lock The lock to set.
- * @deffunc apr_status_t apr_lock_acquire(apr_lock_t *lock)
*/
APR_DECLARE(apr_status_t) apr_lock_acquire(apr_lock_t *lock);
+
+/**
+ * Acquire a lock as a reader
+ * @param lock The lock to set
+ */
+APR_DECLARE(apr_status_t) apr_lock_acquire_read(apr_lock_t *lock);
+
+/**
+ * Acquire a lock as a writer
+ * @param lock The lock to set
+ */
+APR_DECLARE(apr_status_t) apr_lock_acquire_write(apr_lock_t *lock);
/**
* Unlock a protected region.
--- c:\projects\apr\include\arch\win32\locks.h Thu Feb 15 23:41:24
2001
+++ c:\apr\include\arch\win32\locks.h Sat Apr 28 17:25:14 2001
@@ -57,6 +57,10 @@
#include "apr_lock.h"
+#define DOING_NOTHING 0
+#define IS_READING 1
+#define IS_WRITING 2
+
struct apr_lock_t {
apr_pool_t *cntxt;
apr_locktype_e type;
@@ -64,6 +68,14 @@
HANDLE mutex;
CRITICAL_SECTION section;
char *fname;
+ /* Declarations used for the reader writer implementation */
+ apr_uint32_t activeReaders;
+ apr_uint32_t activeWriters;
+ apr_uint32_t waitingReaders;
+ apr_uint32_t waitingWriters;
+ HANDLE blockedReader;
+ HANDLE blockedWriter;
+ apr_uint32_t currOperation;
};
#endif /* LOCKS_H */
--- c:\projects\apr\locks\win32\locks.c Thu Feb 15 23:41:28 2001
+++ c:\apr\locks\win32\locks.c Sat Apr 28 19:04:58 2001
@@ -57,137 +57,276 @@
#include "win32/locks.h"
#include "apr_portable.h"
-APR_DECLARE(apr_status_t) apr_lock_create(apr_lock_t **lock,
- apr_locktype_e type,
- apr_lockscope_e scope,
- const char *fname,
- apr_pool_t *cont)
+APR_DECLARE(apr_status_t) apr_lock_create(apr_lock_t ** lock,
+ apr_locktype_e type,
+ apr_lockscope_e scope,
+ const char *fname,
+ apr_pool_t * cont)
{
apr_lock_t *newlock;
SECURITY_ATTRIBUTES sec;
- newlock = (apr_lock_t *)apr_palloc(cont, sizeof(apr_lock_t));
+ newlock = (apr_lock_t *) apr_palloc(cont, sizeof(apr_lock_t));
newlock->cntxt = cont;
/* ToDo: How to handle the case when no context is available?
- * How to cleanup the storage properly?
- */
+ * How to cleanup the storage properly?
+ */
newlock->fname = apr_pstrdup(cont, fname);
newlock->type = type;
newlock->scope = scope;
+ newlock->activeReaders = 0;
+ newlock->activeWriters = 0;
+ newlock->waitingReaders = 0;
+ newlock->waitingWriters = 0;
+ newlock->currOperation = DOING_NOTHING;
+ if (newlock->type == APR_READWRITE) {
+ newlock->blockedReader = CreateMutex(NULL, FALSE, NULL);
+ newlock->blockedWriter = CreateMutex(NULL, FALSE, NULL);
+ }
+ else {
+ newlock->blockedReader = NULL;
+ newlock->blockedWriter = NULL;
+ }
+
sec.nLength = sizeof(SECURITY_ATTRIBUTES);
sec.lpSecurityDescriptor = NULL;
if (scope == APR_CROSS_PROCESS || scope == APR_LOCKALL) {
- sec.bInheritHandle = TRUE;
+ sec.bInheritHandle = TRUE;
}
else {
- sec.bInheritHandle = FALSE;
+ sec.bInheritHandle = FALSE;
}
if (scope == APR_INTRAPROCESS) {
- InitializeCriticalSection(&newlock->section);
- } else {
- newlock->mutex = CreateMutex(&sec, FALSE, fname);
+ InitializeCriticalSection(&newlock->section);
+ }
+ else {
+ newlock->mutex = CreateMutex(&sec, FALSE, fname);
}
*lock = newlock;
return APR_SUCCESS;
}
-APR_DECLARE(apr_status_t) apr_lock_child_init(apr_lock_t **lock,
- const char *fname,
- apr_pool_t *cont)
+APR_DECLARE(apr_status_t) apr_lock_child_init(apr_lock_t ** lock,
+ const char *fname,
+ apr_pool_t * cont)
{
/* This routine should not be called (and OpenMutex will fail if
called)
* on a INTRAPROCESS lock
*/
- (*lock) = (apr_lock_t *)apr_palloc(cont, sizeof(apr_lock_t));
+ (*lock) = (apr_lock_t *) apr_palloc(cont, sizeof(apr_lock_t));
if ((*lock) == NULL) {
- return APR_ENOMEM;
+ return APR_ENOMEM;
}
(*lock)->fname = apr_pstrdup(cont, fname);
(*lock)->mutex = OpenMutex(MUTEX_ALL_ACCESS, TRUE, fname);
-
+
if ((*lock)->mutex == NULL) {
- return apr_get_os_error();
+ return apr_get_os_error();
}
return APR_SUCCESS;
}
-APR_DECLARE(apr_status_t) apr_lock_acquire(apr_lock_t *lock)
+/*
+ * This is private routine to get the lock
+ * It is made private because both the regular lock routines
+ * and the reader writer lock routines use it
+ */
+static apr_status_t get_lock(apr_lock_t * lock)
{
DWORD rv;
+
if (lock->scope == APR_INTRAPROCESS) {
- EnterCriticalSection(&lock->section);
- return APR_SUCCESS;
- } else {
- rv = WaitForSingleObject(lock->mutex, INFINITE);
-
- if (rv == WAIT_OBJECT_0 || rv == WAIT_ABANDONED) {
- return APR_SUCCESS;
- }
+ EnterCriticalSection(&lock->section);
+ return APR_SUCCESS;
+ }
+ else {
+ rv = WaitForSingleObject(lock->mutex, INFINITE);
+
+ if (rv == WAIT_OBJECT_0 || rv == WAIT_ABANDONED) {
+ return APR_SUCCESS;
+ }
}
return apr_get_os_error();
}
-APR_DECLARE(apr_status_t) apr_lock_release(apr_lock_t *lock)
+static apr_status_t release_lock(apr_lock_t * lock)
{
if (lock->scope == APR_INTRAPROCESS) {
- LeaveCriticalSection(&lock->section);
- return APR_SUCCESS;
- } else {
- if (ReleaseMutex(lock->mutex) == 0) {
- return apr_get_os_error();
- }
+ LeaveCriticalSection(&lock->section);
+ return APR_SUCCESS;
+ }
+ else {
+ if (ReleaseMutex(lock->mutex) == 0) {
+ return apr_get_os_error();
+ }
+ }
+ return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_lock_acquire_write(apr_lock_t * lock)
+{
+ DWORD rv;
+
+ if (lock->type == APR_MUTEX) {
+ return APR_ELOCKTYPE;
+ }
+
+ rv = get_lock(lock);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+
+ if (lock->activeReaders == 0 && lock->activeWriters == 0) {
+ /* there is no active reader or writer, OK to start
writing */
+ lock->activeWriters = 1;
+ lock->currOperation = IS_WRITING;
+ release_lock(lock);
+ }
+ else {
+ /* there is active readers or writer, hold on until
free */
+ lock->waitingWriters++;
+ release_lock(lock);
+ WaitForSingleObject(lock->blockedWriter, INFINITE);
+ }
+ return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_lock_acquire_read(apr_lock_t * lock)
+{
+ DWORD rv;
+
+ if (lock->type == APR_MUTEX) {
+ return APR_ELOCKTYPE;
+ }
+
+ rv = get_lock(lock);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+ if (lock->activeWriters > 0 || lock->waitingWriters > 0) {
+ lock->waitingReaders++;
+ release_lock(lock);
+ WaitForSingleObject(lock->blockedReader, INFINITE);
+ }
+ else {
+ lock->activeReaders++;
+ lock->currOperation = IS_WRITING;
+ release_lock(lock);
}
return APR_SUCCESS;
}
-APR_DECLARE(apr_status_t) apr_lock_destroy(apr_lock_t *lock)
+APR_DECLARE(apr_status_t) apr_lock_acquire(apr_lock_t * lock)
+{
+ /* ToDo: if the lock is a read write what is the default
behaviour?
+ * Right now it is set to return an error
+ */
+ if (lock->type == APR_READWRITE) {
+ return APR_ELOCKTYPE;
+ }
+ return get_lock(lock);
+}
+
+APR_DECLARE(apr_status_t) apr_lock_release(apr_lock_t * lock)
+{
+ DWORD rv;
+
+ if (lock->type == APR_MUTEX) {
+ return release_lock(lock);
+ }
+ else {
+ rv = get_lock(lock);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+ if (lock->currOperation == IS_READING) {
+ lock->activeReaders--;
+ /* last reader thread to finish reading needs
+ * to activate a waiting writer
+ */
+ if (lock->activeReaders == 0 &&
lock->waitingWriters > 0) {
+ lock->activeWriters = 1;
+ lock->waitingWriters--;
+ ReleaseMutex(lock->blockedWriter);
+ }
+ }
+ else if (lock->currOperation == IS_WRITING) {
+ lock->activeWriters = 0;
+ if (lock->waitingReaders > 0) {
+ /* if there are waiting readers,
release them all from read queue */
+ while (lock->waitingReaders > 0) {
+ lock->waitingReaders--;
+ lock->activeReaders++;
+
ReleaseMutex(lock->blockedWriter);
+ }
+ }
+ else if (lock->waitingWriters > 0) {
+ /* no waiting reader and we have
waiting writer,
+ * release 1 writer from write queue
+ */
+ lock->waitingWriters--;
+ ReleaseMutex(lock->blockedWriter);
+ }
+ }
+ lock->currOperation = DOING_NOTHING;
+ release_lock(lock);
+ }
+ return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_lock_destroy(apr_lock_t * lock)
{
if (lock->scope == APR_INTRAPROCESS) {
- DeleteCriticalSection(&lock->section);
- return APR_SUCCESS;
- } else {
- if (CloseHandle(lock->mutex) == 0) {
- return apr_get_os_error();
- }
+ DeleteCriticalSection(&lock->section);
+ }
+ else {
+ if (CloseHandle(lock->mutex) == 0) {
+ return apr_get_os_error();
+ }
+ }
+
+ if (lock->type == APR_READWRITE) {
+ CloseHandle(lock->blockedReader);
+ CloseHandle(lock->blockedWriter);
}
return APR_SUCCESS;
}
-APR_DECLARE(apr_status_t) apr_lock_data_get(apr_lock_t *lock, const
char *key,
- void *data)
+APR_DECLARE(apr_status_t) apr_lock_data_get(apr_lock_t * lock,
+ const char *key, void
*data)
{
return apr_pool_userdata_get(data, key, lock->cntxt);
}
-APR_DECLARE(apr_status_t) apr_lock_data_set(apr_lock_t *lock, void
*data,
- const char *key,
- apr_status_t (*cleanup)
(void *))
+APR_DECLARE(apr_status_t) apr_lock_data_set(apr_lock_t * lock, void
*data,
+ const char *key,
+ apr_status_t(*cleanup)
(void *))
{
return apr_pool_userdata_set(data, key, cleanup, lock->cntxt);
}
-APR_DECLARE(apr_status_t) apr_os_lock_get(apr_os_lock_t *thelock,
- apr_lock_t *lock)
+APR_DECLARE(apr_status_t) apr_os_lock_get(apr_os_lock_t * thelock,
+ apr_lock_t * lock)
{
*thelock = lock->mutex;
return APR_SUCCESS;
}
-APR_DECLARE(apr_status_t) apr_os_lock_put(apr_lock_t **lock,
- apr_os_lock_t *thelock,
- apr_pool_t *cont)
+APR_DECLARE(apr_status_t) apr_os_lock_put(apr_lock_t ** lock,
+ apr_os_lock_t * thelock,
+ apr_pool_t * cont)
{
if (cont == NULL) {
- return APR_ENOPOOL;
+ return APR_ENOPOOL;
}
if ((*lock) == NULL) {
- (*lock) = (apr_lock_t *)apr_palloc(cont, sizeof(apr_lock_t));
- (*lock)->cntxt = cont;
+ (*lock) = (apr_lock_t *) apr_palloc(cont,
sizeof(apr_lock_t));
+ (*lock)->cntxt = cont;
}
(*lock)->mutex = *thelock;
return APR_SUCCESS;
-}
+}