summaryrefslogtreecommitdiff
path: root/locks/os2/thread_cond.c
diff options
context:
space:
mode:
Diffstat (limited to 'locks/os2/thread_cond.c')
-rw-r--r--locks/os2/thread_cond.c150
1 files changed, 142 insertions, 8 deletions
diff --git a/locks/os2/thread_cond.c b/locks/os2/thread_cond.c
index ec6034f55..1b8698e7a 100644
--- a/locks/os2/thread_cond.c
+++ b/locks/os2/thread_cond.c
@@ -23,38 +23,172 @@
#include "apr_arch_file_io.h"
#include <string.h>
+#ifndef DCE_POSTONE
+#define DCE_POSTONE 0x0800 // Post one flag
+#endif
+
+static apr_status_t thread_cond_cleanup(void *data)
+{
+ apr_thread_cond_t *cv = data;
+
+ if (cv->semaphore) {
+ DosCloseEventSem(cv->semaphore);
+ }
+
+ if (cv->mutex) {
+ DosCloseMutexSem(cv->mutex);
+ }
+
+ return APR_SUCCESS;
+}
+
+
+
APR_DECLARE(apr_status_t) apr_thread_cond_create(apr_thread_cond_t **cond,
apr_pool_t *pool)
{
- return APR_ENOTIMPL;
+ int rc;
+ apr_thread_cond_t *cv;
+
+ cv = apr_pcalloc(pool, sizeof(**cond));
+ rc = DosCreateEventSem(NULL, &cv->semaphore, DCE_POSTONE, FALSE);
+
+ if (rc == 0) {
+ rc = DosCreateMutexSem(NULL, &cv->mutex, 0, FALSE);
+ }
+
+ *cond = cv;
+ cv->pool = pool;
+ apr_pool_cleanup_register(cv->pool, cv, thread_cond_cleanup,
+ apr_pool_cleanup_null);
+
+ return APR_FROM_OS_ERROR(rc);
+}
+
+
+
+static apr_status_t thread_cond_timedwait(apr_thread_cond_t *cond,
+ apr_thread_mutex_t *mutex,
+ ULONG timeout_ms )
+{
+ ULONG rc;
+ apr_status_t rv = APR_SUCCESS;
+ int wake = FALSE;
+ unsigned long generation;
+
+ DosRequestMutexSem(cond->mutex, SEM_INDEFINITE_WAIT);
+ cond->num_waiting++;
+ generation = cond->generation;
+ DosReleaseMutexSem(cond->mutex);
+
+ apr_thread_mutex_unlock(mutex);
+
+ do {
+ rc = DosWaitEventSem(cond->semaphore, timeout_ms);
+
+ DosRequestMutexSem(cond->mutex, SEM_INDEFINITE_WAIT);
+
+ if (cond->num_wake) {
+ if (cond->generation != generation) {
+ cond->num_wake--;
+ cond->num_waiting--;
+ rv = APR_SUCCESS;
+ break;
+ } else {
+ wake = TRUE;
+ }
+ }
+ else if (rc != 0) {
+ cond->num_waiting--;
+ rv = APR_TIMEUP;
+ break;
+ }
+
+ DosReleaseMutexSem(cond->mutex);
+
+ if (wake) {
+ wake = FALSE;
+ DosPostEventSem(cond->semaphore);
+ }
+ } while (1);
+
+ DosReleaseMutexSem(cond->mutex);
+ apr_thread_mutex_lock(mutex);
+ return rv;
}
+
+
APR_DECLARE(apr_status_t) apr_thread_cond_wait(apr_thread_cond_t *cond,
apr_thread_mutex_t *mutex)
{
- return APR_ENOTIMPL;
+ return thread_cond_timedwait(cond, mutex, SEM_INDEFINITE_WAIT);
}
+
+
APR_DECLARE(apr_status_t) apr_thread_cond_timedwait(apr_thread_cond_t *cond,
apr_thread_mutex_t *mutex,
- apr_interval_time_t timeout){
- return APR_ENOTIMPL;
+ apr_interval_time_t timeout)
+{
+ ULONG timeout_ms = (timeout >= 0) ? apr_time_as_msec(timeout)
+ : SEM_INDEFINITE_WAIT;
+ return thread_cond_timedwait(cond, mutex, timeout_ms);
}
+
+
APR_DECLARE(apr_status_t) apr_thread_cond_signal(apr_thread_cond_t *cond)
{
- return APR_ENOTIMPL;
+ int wake = FALSE;
+
+ DosRequestMutexSem(cond->mutex, SEM_INDEFINITE_WAIT);
+
+ if (cond->num_waiting > cond->num_wake) {
+ wake = TRUE;
+ cond->num_wake++;
+ cond->generation++;
+ }
+
+ DosReleaseMutexSem(cond->mutex);
+
+ if (wake) {
+ DosPostEventSem(cond->semaphore);
+ }
+
+ return APR_SUCCESS;
}
+
+
APR_DECLARE(apr_status_t) apr_thread_cond_broadcast(apr_thread_cond_t *cond)
{
- return APR_ENOTIMPL;
+ unsigned long num_wake = 0;
+
+ DosRequestMutexSem(cond->mutex, SEM_INDEFINITE_WAIT);
+
+ if (cond->num_waiting > cond->num_wake) {
+ num_wake = cond->num_waiting - cond->num_wake;
+ cond->num_wake = cond->num_waiting;
+ cond->generation++;
+ }
+
+ DosReleaseMutexSem(cond->mutex);
+
+ for (; num_wake; num_wake--) {
+ DosPostEventSem(cond->semaphore);
+ }
+
+ return APR_SUCCESS;
}
+
+
APR_DECLARE(apr_status_t) apr_thread_cond_destroy(apr_thread_cond_t *cond)
{
- return APR_ENOTIMPL;
+ return apr_pool_cleanup_run(cond->pool, cond, thread_cond_cleanup);
}
-APR_POOL_IMPLEMENT_ACCESSOR(thread_cond)
+
+APR_POOL_IMPLEMENT_ACCESSOR(thread_cond)