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;