blob: 9acd81d1d9941caebf6036f305998b183d861449 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file os_condvar.c
* @brief Binding of hycond to condition variables provided by Pthreads
*/
#include "thread_private.h"
#include <open/hythread_ext.h>
/** @name Conditional variable
*/
//@{
/**
* waits on a condition variable, directly using OS interfaces.
*
* This function does not implement interruptability and thread state
* functionality, thus the caller of this function have to handle it.
*/
int os_cond_timedwait(hycond_t *cond, osmutex_t *mutex, I_64 ms, IDATA nano)
{
int r = 0;
if (!ms && !nano) {
r = pthread_cond_wait(cond, mutex);
} else {
// the main point here is to translate time from ms:nano
// format into sec:nano format (acceptable by pthread)
apr_time_t now = apr_time_now();
// translate 'now' into: seconds + nanos
I_64 Nsec = apr_time_sec(now);
I_64 Nnsec = (apr_time_usec(now) % APR_USEC_PER_SEC) * ((1000*1000*1000) / APR_USEC_PER_SEC);
// translate delay method parameters ('ms' and 'nano') into:
// seconds + nanos (taking care about overflow)
I_64 Dsec = (ms / 1000) + (nano / (1000 * 1000 * 1000));
I_64 Dnsec = (ms % 1000) * (1000 * 1000) + (nano % (1000 * 1000 * 1000));
Dsec = Dsec + (Dnsec / (1000 * 1000 * 1000));
Dnsec = Dnsec % (1000 * 1000 * 1000);
// calculating result sec:nanos values
// (taking care about overflow as well)
I_64 Rsec = Dsec + Nsec + (Dnsec + Nnsec) / (1000 * 1000 * 1000);
I_64 Rnsec = (Dnsec + Nnsec) % (1000 * 1000 * 1000);
// wrap the resulting wake up time (absolute time) into struct
// acceptable by pthread_cond_timedwait()
struct timespec wakeup_time;
// final boundary checks: pthread struct sec is 32 bit
if (Rsec <= 0x7FFFFFFF) {
wakeup_time.tv_sec = Rsec;
} else {
wakeup_time.tv_sec = 0x7FFFFFFF;
}
// final boundary checks: pthread struct nanos is 32 bit as well
if (Rnsec <= 0x7FFFFFFF) {
wakeup_time.tv_nsec = Rnsec;
} else {
wakeup_time.tv_nsec = 0x7FFFFFFF;
}
r = pthread_cond_timedwait(cond, mutex, &wakeup_time);
}
if (r == ETIMEDOUT)
r = TM_ERROR_TIMEOUT;
else if (r == EINTR)
r = TM_ERROR_INTERRUPT;
return r;
}
/**
* Creates and initializes condition variable.
*
* @param[in] cond the address of the condition variable.
* @return 0 on success, non-zero otherwise.
*/
IDATA VMCALL hycond_create (hycond_t *cond) {
return pthread_cond_init(cond, NULL);
}
/**
* Signals a single thread that is blocking on the given condition variable
* to wake up.
*
* @param[in] cond the condition variable on which to produce the signal.
* @sa apr_thread_cond_signal()
*/
IDATA VMCALL hycond_notify (hycond_t *cond) {
return pthread_cond_signal(cond);
}
/**
* Signals all threads blocking on the given condition variable.
*
* @param[in] cond the condition variable on which to produce the broadcast.
* @sa apr_thread_cond_broadcast()
*/
IDATA VMCALL hycond_notify_all (hycond_t *cond) {
return pthread_cond_broadcast(cond);
}
/**
* Destroys the condition variable and releases the associated memory.
*
* @param[in] cond the condition variable to destroy
* @sa apr_thread_cond_destroy()
*/
IDATA VMCALL hycond_destroy (hycond_t *cond) {
return pthread_cond_destroy(cond);
}
//@}