apr-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Aaron Bannert <aa...@clove.org>
Subject [PATCH] add apr_thread_mutex_t on unix, stubs elsewhere
Date Thu, 30 Aug 2001 17:43:41 GMT
This is the first installment of my proposed new APR lock API. This
patch implements apr_thread_mutex_t on UNIX -- tested on Solaris (8)
and Linux (2.4). A new test was added to apr/test/testlock that verifies
that this lock is working. This is just the first patch of many to come,
but applying this gives us a framework to work from if anyone else wants
to jump in and help.

I left stubs in for other platforms, but I'll leave it up to the
respective experts to migrate the code. If I get time I may come back
and try to get this as close as I can on other platforms, but no promises.

p.s. I don't have numbers, but using this lock instead of
apr_lock_t/APR_INTRAPROC has the potential to be much faster on highly
used locks, since there are no more function pointers to dereference.

-aaron


Index: include/apr_lock.h
===================================================================
RCS file: /home/cvspublic/apr/include/apr_lock.h,v
retrieving revision 1.30
diff -u -r1.30 apr_lock.h
--- include/apr_lock.h	2001/08/17 03:54:04	1.30
+++ include/apr_lock.h	2001/08/30 17:10:35
@@ -82,6 +82,18 @@
 
 typedef struct apr_lock_t    apr_lock_t;
 
+typedef struct apr_thread_mutex_t apr_thread_mutex_t;
+
+#if 0
+typedef struct apr_proc_mutex_t apr_proc_mutex_t;
+
+typedef struct apr_thread_rwlock_t apr_thread_rwlock_t;
+
+typedef struct apr_proc_rwlock_t apr_proc_rwlock_t;
+
+typedef struct apr_thread_cond_t apr_thread_cond_t;
+#endif
+
 /*   Function definitions */
 
 /**
@@ -231,6 +243,189 @@
                                              apr_pool_t *pool);
 #endif /* APR_HAS_LOCK_CREATE_NP */
 /** @} */
+
+
+
+/**
+ * Create and initialize a mutex that can be used to synchronize threads.
+ * @param mutex the memory address where the newly created mutex will be
+ *        stored.
+ * @param pool the pool from which to allocate the mutex.
+ */
+APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex,
+                                                  apr_pool_t *pool);
+/**
+ * Acquire the lock for the given mutex. If the mutex is already locked,
+ * the current thread will be put to sleep until the lock becomes available.
+ * @param mutex the mutex on which to acquire the lock.
+ */
+APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex);
+
+/**
+ * Attempt to acquire the lock for the given mutex. If the mutex has already
+ * been acquired, the call returns immediately with APR_EBUSY. Note: it
+ * is important that the APR_STATUS_IS_EBUSY(s) macro be used to determine
+ * if the return value was APR_EBUSY, for portability reasons.
+ * @param mutex the mutex on which to attempt the lock acquiring.
+ */
+APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex);
+
+/**
+ * Release the lock for the given mutex.
+ * @param mutex the mutex from which to release the lock.
+ */
+APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex);
+
+/**
+ * Destroy the mutex and free the memory associated with the lock.
+ * @param mutex the mutex to destroy.
+ */
+APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex);
+
+
+#if 0
+/**
+ * Create and initialize a mutex that can be used to synchronize processes.
+ * @param mutex the memory address where the newly created mutex will be
+ *        stored.
+ * @param fname A file name to use if the lock mechanism requires one.  This
+ *        argument should always be provided.  The lock code itself will
+ *        determine if it should be used.
+ * @param pool the pool from which to allocate the mutex.
+ */
+APR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex,
+                                                const char *fname,
+                                                apr_pool_t *pool);
+/**
+ * Acquire the lock for the given mutex. If the mutex is already locked,
+ * the current thread will be put to sleep until the lock becomes available.
+ * @param mutex the mutex on which to acquire the lock.
+ */
+
+APR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_thread_mutex_t *mutex);
+/**
+ * Release the lock for the given mutex.
+ * @param mutex the mutex from which to release the lock.
+ */
+APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_thread_mutex_t *mutex);
+
+
+
+/**
+ * Create and initialize a read-write lock that can be used to synchronize
+ * threads.
+ * @param rwlock the memory address where the newly created readwrite lock
+ *        will be stored.
+ * @param pool the pool from which to allocate the mutex.
+ */
+APR_DECLARE(apr_status_t) apr_thread_rwlock_create(apr_thread_rwlock_t **rwlock,
+                                                   apr_pool_t *pool);
+/**
+ * Acquire a shared-read lock on the given read-write lock. This will allow
+ * multiple threads to enter the same critical section while they have acquired
+ * the read lock.
+ * @param rwlock the read-write lock on which to acquire the shared read.
+ */
+APR_DECLARE(apr_status_t) apr_thread_rwlock_rdlock(apr_thread_rwlock_t *rwlock);
+
+/**
+ * Acquire an exclusive-write lock on the given read-write lock. This will
+ * allow only one single thread to enter the critical sections. If there
+ * are any threads currently holding thee read-lock, this thread is put to
+ * sleep until it can have exclusive access to the lock.
+ * @param rwlock the read-write lock on which to acquire the exclusive write.
+ */
+APR_DECLARE(apr_status_t) apr_thread_rwlock_wrlock(apr_thread_rwlock_t *rwlock);
+
+/**
+ * Release either the read or write lock currently held by the calling thread
+ * associated with the given read-write lock.
+ * @param rwlock the read-write lock rom which to release the lock.
+ */
+APR_DECLARE(apr_status_t) apr_thread_rwlock_unlock(apr_thread_rwlock_t *rwlock);
+
+/**
+ * Create and initialize a read-write lock that can be used to synchronize
+ * processes.
+ * @param rwlock the memory address where the newly created readwrite lock
+ *        will be stored.
+ * @param fname A file name to use if the lock mechanism requires one.  This
+ *        argument should always be provided.  The lock code itself will
+ *        determine if it should be used.
+ * @param pool the pool from which to allocate the mutex.
+ */
+APR_DECLARE(apr_status_t) apr_proc_rwlock_create(apr_proc_rwlock_t **rwlock,
+                                                 const char *fname,
+                                                 apr_pool_t *pool);
+
+/**
+ * Acquire a shared-read lock on the given read-write lock. This will allow
+ * multiple threads to enter the same critical section while they have acquired
+ * the read lock.
+ * @param rwlock the read-write lock on which to acquire the shared read.
+ */
+APR_DECLARE(apr_status_t) apr_proc_rwlock_rdlock(apr_proc_rwlock_t *rwlock);
+
+/**
+ * Acquire an exclusive-write lock on the given read-write lock. This will
+ * allow only one single thread to enter the critical sections. If there
+ * are any threads currently holding thee read-lock, this thread is put to
+ * sleep until it can have exclusive access to the lock.
+ * @param rwlock the read-write lock on which to acquire the exclusive write.
+ */
+APR_DECLARE(apr_status_t) apr_proc_rwlock_wrlock(apr_proc_rwlock_t *rwlock);
+
+/**
+ * Release either the read or write lock currently held by the calling thread
+ * associated with the given read-write lock.
+ * @param rwlock the read-write lock rom which to release the lock.
+ */
+APR_DECLARE(apr_status_t) apr_proc_rwlock_unlock(apr_proc_rwlock_t *rwlock);
+
+
+/**
+ * Create and initialize a condition variable that can be used to signal
+ * and schedule threads in a single process.
+ * @param cond the memory address where the newly created condition variable
+ *        will be stored.
+ * @param pool the pool from which to allocate the mutex.
+ */
+APR_DECLARE(apr_status_t) apr_thread_cond_create(apr_thread_cond_t **cond,
+                                                 apr_pool_t *pool);
+/**
+ * Put the active calling thread to sleep until signaled to wake up. Each
+ * condition variable must be associated with a mutex, and that mutex must
+ * be locked before  calling this function, or the behavior will be
+ * undefined. As the calling thread is put to sleep, the given mutex
+ * will be simultaneously released; and as this thread wakes up the lock
+ * is again simultaneously acquired.
+ * @param cond the condition variable on which to block.
+ * @param mutex the mutex that must be locked upon entering this function,
+ *        is released while the thread is asleep, and is again acquired before
+ *        returning from this function.
+ */
+APR_DECLARE(apr_status_t) apr_thread_cond_wait(apr_thread_cond_t *cond,
+                                               apr_thread_mutex_t *mutex);
+
+/**
+ * Signals a singla thread, if one exists, that is blocking on the given
+ * condition variable. That thread is then scheduled to wake up and acquire
+ * the associated mutex. Although it is not required, if predictible schedule
+ * is desired, that mutex must be locked while calling this function.
+ * @param cond the condition variable on which to produce the signal.
+ */
+APR_DECLARE(apr_status_t) apr_thread_cond_signal(apr_thread_cond_t *cond);
+/**
+ * Signals all threads blocking on the given condition variable.
+ * Each thread that was signaled is then schedule to wake up and acquire
+ * the associated mutex. This will happen in a serialized manner.
+ * @param cond the condition variable on which to produce the broadcast.
+ */
+APR_DECLARE(apr_status_t) apr_thread_cond_broadcast(apr_thread_cond_t *cond);
+
+#endif
+
+
 #ifdef __cplusplus
 }
 #endif
Index: include/arch/beos/locks.h
===================================================================
RCS file: /home/cvspublic/apr/include/arch/beos/locks.h,v
retrieving revision 1.19
diff -u -r1.19 locks.h
--- include/arch/beos/locks.h	2001/06/29 08:51:30	1.19
+++ include/arch/beos/locks.h	2001/08/30 17:10:35
@@ -84,5 +84,8 @@
     thread_id writer;
 };
 
+struct apr_thread_mutex_t {
+};
+
 #endif  /* LOCKS_H */
 
Index: include/arch/netware/locks.h
===================================================================
RCS file: /home/cvspublic/apr/include/arch/netware/locks.h,v
retrieving revision 1.1
diff -u -r1.1 locks.h
--- include/arch/netware/locks.h	2001/08/15 00:17:01	1.1
+++ include/arch/netware/locks.h	2001/08/30 17:10:35
@@ -67,5 +67,8 @@
     char *fname;
 };
 
+struct apr_thread_mutex_t {
+};
+
 #endif  /* LOCKS_H */
 
Index: include/arch/os2/locks.h
===================================================================
RCS file: /home/cvspublic/apr/include/arch/os2/locks.h,v
retrieving revision 1.14
diff -u -r1.14 locks.h
--- include/arch/os2/locks.h	2001/06/06 18:11:22	1.14
+++ include/arch/os2/locks.h	2001/08/30 17:10:35
@@ -69,5 +69,8 @@
     TIB *tib;
 };
 
+struct apr_thread_mutex_t {
+};
+
 #endif  /* LOCKS_H */
 
Index: include/arch/unix/locks.h
===================================================================
RCS file: /home/cvspublic/apr/include/arch/unix/locks.h,v
retrieving revision 1.37
diff -u -r1.37 locks.h
--- include/arch/unix/locks.h	2001/08/11 07:32:54	1.37
+++ include/arch/unix/locks.h	2001/08/30 17:10:35
@@ -171,6 +171,13 @@
      */    
 };
 
+#ifdef APR_HAS_THREADS
+struct apr_thread_mutex_t {
+    pthread_mutex_t *mutex;
+    apr_pool_t *pool;
+};
+#endif
+
 #if APR_HAS_THREADS
 extern const apr_unix_lock_methods_t apr_unix_intra_methods;
 #endif
Index: include/arch/win32/locks.h
===================================================================
RCS file: /home/cvspublic/apr/include/arch/win32/locks.h,v
retrieving revision 1.12
diff -u -r1.12 locks.h
--- include/arch/win32/locks.h	2001/06/06 18:11:34	1.12
+++ include/arch/win32/locks.h	2001/08/30 17:10:35
@@ -66,5 +66,8 @@
     char *fname;
 };
 
+struct apr_thread_mutex_t {
+};
+
 #endif  /* LOCKS_H */
 
Index: locks/beos/locks.c
===================================================================
RCS file: /home/cvspublic/apr/locks/beos/locks.c,v
retrieving revision 1.34
diff -u -r1.34 locks.c
--- locks/beos/locks.c	2001/08/10 21:04:47	1.34
+++ locks/beos/locks.c	2001/08/30 17:10:35
@@ -453,3 +453,34 @@
     return APR_SUCCESS;
 }
 
+static apr_status_t thread_mutex_cleanup(void *data)
+{
+    return APR_NOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex,
+                                                  apr_pool_t *pool)
+{
+    return APR_NOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex)
+{
+    return APR_NOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex)
+{
+    return APR_NOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex)
+{
+    return APR_NOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex)
+{
+    return APR_NOTIMPL;
+}
+
Index: locks/netware/locks.c
===================================================================
RCS file: /home/cvspublic/apr/locks/netware/locks.c,v
retrieving revision 1.1
diff -u -r1.1 locks.c
--- locks/netware/locks.c	2001/08/06 15:50:49	1.1
+++ locks/netware/locks.c	2001/08/30 17:10:35
@@ -311,3 +311,35 @@
     }
     return APR_SUCCESS;
 }    
+
+static apr_status_t thread_mutex_cleanup(void *data)
+{
+    return APR_NOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex,
+                                                  apr_pool_t *pool)
+{
+    return APR_NOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex)
+{
+    return APR_NOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex)
+{
+    return APR_NOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex)
+{
+    return APR_NOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex)
+{
+    return APR_NOTIMPL;
+}
+
Index: locks/os2/locks.c
===================================================================
RCS file: /home/cvspublic/apr/locks/os2/locks.c,v
retrieving revision 1.35
diff -u -r1.35 locks.c
--- locks/os2/locks.c	2001/08/10 21:04:47	1.35
+++ locks/os2/locks.c	2001/08/30 17:10:35
@@ -282,3 +282,35 @@
 {
     return apr_pool_userdata_set(data, key, cleanup, lock->pool);
 }
+
+static apr_status_t thread_mutex_cleanup(void *data)
+{
+    return APR_NOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex,
+                                                  apr_pool_t *pool)
+{
+    return APR_NOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex)
+{
+    return APR_NOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex)
+{
+    return APR_NOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex)
+{
+    return APR_NOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex)
+{
+    return APR_NOTIMPL;
+}
+
Index: locks/unix/intraproc.c
===================================================================
RCS file: /home/cvspublic/apr/locks/unix/intraproc.c,v
retrieving revision 1.27
diff -u -r1.27 intraproc.c
--- locks/unix/intraproc.c	2001/07/19 00:11:57	1.27
+++ locks/unix/intraproc.c	2001/08/30 17:10:35
@@ -226,4 +226,126 @@
 };
 #endif
 
+
+static apr_status_t thread_mutex_cleanup(void *data)
+{
+    apr_thread_mutex_t *mutex = (apr_thread_mutex_t *)data;
+    apr_status_t stat;
+
+    pthread_mutex_unlock(mutex->mutex);
+    stat = pthread_mutex_destroy(mutex->mutex);
+#ifdef PTHREAD_SETS_ERRNO
+    if (stat) {
+        stat = errno;
+    }
+#endif
+    return stat;
+} 
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex,
+                                                  apr_pool_t *pool)
+{
+    apr_thread_mutex_t *new_mutex;
+    pthread_mutexattr_t mattr;
+    apr_status_t stat;
+
+    new_mutex = (apr_thread_mutex_t *)apr_pcalloc(pool,
+                                                  sizeof(apr_thread_mutex_t));
+
+    if (new_mutex == NULL) {
+        return errno;
+    }
+
+    new_mutex->pool = pool;
+    new_mutex->mutex = (pthread_mutex_t *)apr_palloc(pool, 
+                                                     sizeof(pthread_mutex_t));
+
+    if (new_mutex->mutex == NULL) {
+        return errno;
+    }
+
+    if ((stat = pthread_mutexattr_init(&mattr))) {
+#ifdef PTHREAD_SETS_ERRNO
+        stat = errno;
+#endif
+        thread_mutex_cleanup(new_mutex);
+        return stat;
+    }
+
+    if ((stat = pthread_mutex_init(new_mutex->mutex, &mattr))) {
+#ifdef PTHREAD_SETS_ERRNO
+        stat = errno;
+#endif
+        thread_mutex_cleanup(new_mutex);
+        return stat;
+    }
+
+    if ((stat = pthread_mutexattr_destroy(&mattr))) {
+#ifdef PTHREAD_SETS_ERRNO
+        stat = errno;
+#endif
+        thread_mutex_cleanup(new_mutex);
+        return stat;
+    }
+
+    apr_pool_cleanup_register(new_mutex->pool,
+                              (void *)new_mutex, thread_mutex_cleanup,
+                              apr_pool_cleanup_null);
+
+    *mutex = new_mutex;
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex)
+{
+    apr_status_t stat;
+
+    stat = pthread_mutex_lock(mutex->mutex);
+#ifdef PTHREAD_SETS_ERRNO
+    if (stat) {
+        stat = errno;
+    }
+#endif
+    return stat;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex)
+{
+    apr_status_t stat;
+
+    stat = pthread_mutex_trylock(mutex->mutex);
+#ifdef PTHREAD_SETS_ERRNO
+    if (stat) {
+        stat = errno;
+    }
+#endif
+    /* Normalize the return code. */
+    if (stat == EBUSY)
+        stat = APR_EBUSY;
+    return stat;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex)
+{
+    apr_status_t status;
+
+    status = pthread_mutex_unlock(mutex->mutex);
+#ifdef PTHREAD_SETS_ERRNO
+    if (status) {
+        status = errno;
+    }
+#endif
+    return status;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex)
+{
+    apr_status_t stat;
+    if ((stat = thread_mutex_cleanup(mutex)) == APR_SUCCESS) {
+        apr_pool_cleanup_kill(mutex->pool, mutex, thread_mutex_cleanup);
+        return APR_SUCCESS;
+    }
+    return stat;
+}
+
 #endif /* APR_HAS_THREADS */
Index: locks/unix/locks.c
===================================================================
RCS file: /home/cvspublic/apr/locks/unix/locks.c,v
retrieving revision 1.62
diff -u -r1.62 locks.c
--- locks/unix/locks.c	2001/08/10 21:04:47	1.62
+++ locks/unix/locks.c	2001/08/30 17:10:35
@@ -408,3 +408,4 @@
     return APR_SUCCESS;
 }
  
+
Index: locks/win32/locks.c
===================================================================
RCS file: /home/cvspublic/apr/locks/win32/locks.c,v
retrieving revision 1.45
diff -u -r1.45 locks.c
--- locks/win32/locks.c	2001/07/19 00:11:57	1.45
+++ locks/win32/locks.c	2001/08/30 17:10:35
@@ -261,3 +261,35 @@
     (*lock)->mutex = *thelock;
     return APR_SUCCESS;
 }    
+
+static apr_status_t thread_mutex_cleanup(void *data)
+{
+    return APR_NOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex,
+                                                  apr_pool_t *pool)
+{
+    return APR_NOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex)
+{
+    return APR_NOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex)
+{
+    return APR_NOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex)
+{
+    return APR_NOTIMPL;
+}
+
+APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex)
+{
+    return APR_NOTIMPL;
+}
+
Index: test/testlock.c
===================================================================
RCS file: /home/cvspublic/apr/test/testlock.c,v
retrieving revision 1.5
diff -u -r1.5 testlock.c
--- test/testlock.c	2001/08/01 21:06:26	1.5
+++ test/testlock.c	2001/08/30 17:10:35
@@ -75,6 +75,7 @@
 
 void * APR_THREAD_FUNC thread_rw_func(apr_thread_t *thd, void *data);
 void * APR_THREAD_FUNC thread_function(apr_thread_t *thd, void *data);
+void * APR_THREAD_FUNC thread_mutex_function(apr_thread_t *thd, void *data);
 apr_status_t test_exclusive(void);
 apr_status_t test_rw(void);
 apr_status_t test_multiple_locking(void);
@@ -82,6 +83,7 @@
 
 apr_file_t *in, *out, *err;
 apr_lock_t *thread_rw_lock, *thread_lock;
+apr_thread_mutex_t *thread_mutex;
 apr_pool_t *pool;
 int i = 0, x = 0;
 
@@ -135,6 +137,31 @@
     return NULL;
 } 
 
+void * APR_THREAD_FUNC thread_mutex_function(apr_thread_t *thd, void *data)
+{
+    int exitLoop = 1;
+
+    /* slight delay to allow things to settle */
+    apr_sleep (1);
+    
+    while (1)
+    {
+        apr_thread_mutex_lock(thread_mutex);
+        if (i == MAX_ITER)
+            exitLoop = 0;
+        else 
+        {
+            i++;
+            x++;
+        }
+        apr_thread_mutex_unlock(thread_mutex);
+
+        if (!exitLoop)
+            break;
+    }
+    return NULL;
+} 
+
 int test_rw(void)
 {
     apr_thread_t *t1, *t2, *t3, *t4;
@@ -277,6 +304,54 @@
     return APR_SUCCESS;
 }
 
+apr_status_t test_thread_mutex(void)
+{
+    apr_thread_t *t1, *t2, *t3, *t4;
+    apr_status_t s1, s2, s3, s4;
+
+    printf("thread_mutex test\n");
+    printf("%-60s", "    Initializing the mutex");
+    s1 = apr_thread_mutex_create(&thread_mutex, pool);
+
+    if (s1 != APR_SUCCESS) {
+        printf("Failed!\n");
+        return s1;
+    }
+    printf("OK\n");
+
+    i = 0;
+    x = 0;
+
+    printf("%-60s", "    Starting all the threads"); 
+    s1 = apr_thread_create(&t1, NULL, thread_mutex_function, NULL, pool);
+    s2 = apr_thread_create(&t2, NULL, thread_mutex_function, NULL, pool);
+    s3 = apr_thread_create(&t3, NULL, thread_mutex_function, NULL, pool);
+    s4 = apr_thread_create(&t4, NULL, thread_mutex_function, NULL, pool);
+    if (s1 != APR_SUCCESS || s2 != APR_SUCCESS || 
+        s3 != APR_SUCCESS || s4 != APR_SUCCESS) {
+        printf("Failed!\n");
+        return s1;
+    }
+    printf("OK\n");
+
+    printf("%-60s", "    Waiting for threads to exit");
+    apr_thread_join(&s1, t1);
+    apr_thread_join(&s2, t2);
+    apr_thread_join(&s3, t3);
+    apr_thread_join(&s4, t4);
+    printf("OK\n");
+
+    if (x != MAX_ITER) {
+        fprintf(stderr, "pthread_mutex don't appear to work!"
+                        "  x = %d instead of %d\n",
+                x, MAX_ITER);
+    }
+    else {
+        printf("Test passed\n");
+    }
+    return APR_SUCCESS;
+}
+
 int main(void)
 {
     apr_status_t rv;
@@ -306,6 +381,12 @@
         fprintf(stderr,"RW Lock test failed : [%d] %s\n",
                 rv, apr_strerror(rv, (char*)errmsg, 200));
         exit(-4);
+    }
+
+    if ((rv = test_thread_mutex()) != APR_SUCCESS) {
+        fprintf(stderr,"thread_mutex test failed : [%d] %s\n",
+                rv, apr_strerror(rv, (char*)errmsg, 200));
+        exit(-5);
     }
 
     return 0;

Mime
View raw message