Commit c7a33d2d authored by Éric Thiébaut's avatar Éric Thiébaut
Browse files

Call TAO library functions to return a consistent status

parent 1c4d4965
......@@ -19,6 +19,7 @@
#include <stdbool.h>
#include <stdatomic.h>
#include "tao-basics.h"
#include "tao-locks.h"
#include "tao-errors.h"
#include "tao-generic.h"
......@@ -26,350 +27,6 @@
#include "tao-remote-objects-private.h"
#include "tao-rwlocked-objects-private.h"
//-----------------------------------------------------------------------------
// TIME
static inline tao_status get_time(
const char* func,
int id,
tao_time* t)
{
struct timespec ts;
if (clock_gettime(id, &ts) != 0) {
*t = TAO_UNKNOWN_TIME;
tao_store_system_error(func);
return TAO_ERROR;
}
t->sec = ts.tv_sec;
t->nsec = ts.tv_nsec;
return TAO_OK;
}
static inline tao_timeout get_absolute_timeout(
const char* func,
tao_time* abstime,
double secs)
{
// Get current time as soon as possible, so that the time consumed by the
// following computations is automatically taken into account. The
// absolute time assumed by POSIX threads is given by CLOCK_REALTIME.
if (get_time(func, CLOCK_REALTIME, abstime) != TAO_OK) {
return TAO_TIMEOUT_ERROR;
}
if (isnan(secs)) {
tao_store_error(func, TAO_BAD_ARGUMENT);
return TAO_TIMEOUT_ERROR;
}
if (fabs(secs) < TAO_TIMEOUT_MIN) {
// The time adjustment, rounded to the assumed clock resolution, is
// less than the assumed clock resolution.
return TAO_TIMEOUT_NOW;
}
// Add the relative timeout to the actual time. First just add the number
// of nanoseconds and normalize the result, then check for
// `tao_time_member` overflow. We are assuming that current time since
// the Epoch is not near the limit +/-TAO_MAX_TIME_SECONDS.
double int_secs = floor(secs); // 0 ≤ secs - int_secs < 1s
tao_time_member abstime_s = abstime->sec;
tao_time_member abstime_ns = abstime->nsec + lround((secs - int_secs)*1e9);
TAO_NORMALIZE_TIME(tao_time_member, abstime_s, abstime_ns);
int_secs += (double)abstime_s;
if (int_secs >= 0) {
if (int_secs > (double)TAO_MAX_TIME_SECONDS) {
abstime->sec = TAO_MAX_TIME_SECONDS;
abstime->nsec = TAO_NANOSECONDS_PER_SECOND - 1;
return TAO_TIMEOUT_NEVER;
} else {
abstime->sec = (tao_time_member)int_secs;
abstime->nsec = abstime_ns;
return TAO_TIMEOUT_FUTURE;
}
} else {
if (int_secs < (double)TAO_MIN_TIME_SECONDS) {
abstime->sec = TAO_MIN_TIME_SECONDS;
abstime->nsec = 0;
} else {
abstime->sec = (tao_time_member)int_secs;
abstime->nsec = abstime_ns;
}
return TAO_TIMEOUT_PAST;
}
}
//-----------------------------------------------------------------------------
// MUTEXES AND CONDITION VARIABLES
// NOTE: It is assumed that waiting for a condition always re-acquire the lock
// before returning, even in case of error.
// Unlock mutex.
static inline tao_status unlock_mutex(
const char* func,
tao_mutex* mutex)
{
int code = pthread_mutex_unlock(mutex);
if (code != 0) {
tao_store_error(func, code);
return TAO_ERROR;
}
return TAO_OK;
}
// Unlock mutex. This version is useful to unlock and update status.
static inline tao_status unlock_mutex_with_status(
const char* func,
tao_mutex* mutex,
tao_status status)
{
return unlock_mutex(func, mutex) == TAO_OK ? status : TAO_ERROR;
}
// Lock mutex.
static inline tao_status lock_mutex(
const char* func,
tao_mutex* mutex)
{
int code = pthread_mutex_lock(mutex);
if (code != 0) {
tao_store_error(func, code);
return TAO_ERROR;
}
return TAO_OK;
}
// Attempt to lock mutex without blocking.
static inline tao_status try_lock_mutex(
const char* func,
tao_mutex* mutex)
{
int code = pthread_mutex_trylock(mutex);
if (code != 0) {
tao_store_error(func, code);
return TAO_ERROR;
}
return TAO_OK;
}
// Attempt to lock mutex without blocking more than given absolute time limit.
static inline tao_status abstimed_lock_mutex(
const char* func,
tao_mutex* mutex,
const tao_time* abstime)
{
struct timespec ts = {
.tv_sec = abstime->sec,
.tv_nsec = abstime->nsec,
};
int code = pthread_mutex_timedlock(mutex, &ts);
if (code != 0) {
tao_store_error(func, code);
return TAO_ERROR;
}
return TAO_OK;
}
// Attempt to lock mutex without blocking longer than given number of seconds.
static inline tao_status timed_lock_mutex(
const char* func,
tao_mutex* mutex,
double secs)
{
tao_time abstime;
switch (get_absolute_timeout(func, &abstime, secs)) {
case TAO_TIMEOUT_PAST:
return TAO_TIMEOUT;
case TAO_TIMEOUT_NOW:
return try_lock_mutex(func, mutex);
case TAO_TIMEOUT_FUTURE:
return abstimed_lock_mutex(func, mutex, &abstime);
case TAO_TIMEOUT_NEVER:
return lock_mutex(func, mutex);
default:
return TAO_ERROR;
}
}
// Signal a condition to one other thread or process.
static inline tao_status signal_condition(
const char* func,
tao_cond* cond)
{
int code = pthread_cond_signal(cond);
if (code != 0) {
tao_store_error(func, code);
return TAO_ERROR;
}
return TAO_OK;
}
// Signal a condition to all other threads and processes.
static inline tao_status broadcast_condition(
const char* func,
tao_cond* cond)
{
int code = pthread_cond_broadcast(cond);
if (code != 0) {
tao_store_error(func, code);
return TAO_ERROR;
}
return TAO_OK;
}
// Wait on a condition.
static inline tao_status wait_condition(
const char* func,
tao_cond* cond,
tao_mutex* mutex)
{
int code = pthread_cond_wait(cond, mutex);
if (code != 0) {
tao_store_error(func, code);
return TAO_ERROR;
}
return TAO_OK;
}
// Wait on a condition but no longer than given absolute time limit.
static inline tao_status abstimed_wait_condition(
const char* func,
tao_cond* cond,
tao_mutex* mutex,
const tao_time* abstime)
{
struct timespec ts = {
.tv_sec = abstime->sec,
.tv_nsec = abstime->nsec,
};
int code = pthread_cond_timedwait(cond, mutex, &ts);
if (code != 0) {
tao_store_error(func, code);
return TAO_ERROR;
}
return TAO_OK;
}
// Wait on a condition but no longer than given number of seconds.
static inline tao_status timed_wait_condition(
const char* func,
tao_cond* cond,
tao_mutex* mutex,
double secs)
{
tao_time abstime;
switch(get_absolute_timeout(func, &abstime, secs)) {
case TAO_TIMEOUT_PAST:
case TAO_TIMEOUT_NOW:
return TAO_TIMEOUT;
case TAO_TIMEOUT_FUTURE:
return abstimed_wait_condition(func, cond, mutex, &abstime);
case TAO_TIMEOUT_NEVER:
return wait_condition(func, cond, mutex);
default:
return TAO_ERROR;
}
}
//-----------------------------------------------------------------------------
// SHARED OBJECTS
// Unlock a shared object.
static inline tao_status shared_object_unlock(
const char* func,
tao_shared_object* obj)
{
return unlock_mutex(func, &obj->mutex);
}
// Unlock a shared object. This version is useful to unlock and update status.
static inline tao_status shared_object_unlock_with_status(
const char* func,
tao_shared_object* obj,
tao_status status)
{
return unlock_mutex_with_status(func, &obj->mutex, status);
}
// Lock a shared object.
static inline tao_status shared_object_lock(
const char* func,
tao_shared_object* obj)
{
return lock_mutex(func, &obj->mutex);
}
// Attempt to lock a shared object without blocking.
static inline tao_status shared_object_try_lock(
const char* func,
tao_shared_object* obj)
{
return try_lock_mutex(func, &obj->mutex);
}
// Attempt to lock a shared object without blocking for longer than an absolute
// time limit.
static inline tao_status shared_object_abstimed_lock(
const char* func,
tao_shared_object* obj,
const tao_time* abstime)
{
return abstimed_lock_mutex(func, &obj->mutex, abstime);
}
// Attempt to lock a shared object without blocking for longer than a given
// number of seconds.
static inline tao_status shared_object_timed_lock(
const char* func,
tao_shared_object* obj,
double secs)
{
return timed_lock_mutex(func, &obj->mutex, secs);
}
// Signal changes in a shared object to one other thread or process.
static inline tao_status shared_object_signal_condition(
const char* func,
tao_shared_object* obj)
{
return signal_condition(func, &obj->cond);
}
// Signal changes in a shared object to all other threads and processes.
static inline tao_status shared_object_broadcast_condition(
const char* func,
tao_shared_object* obj)
{
return broadcast_condition(func, &obj->cond);
}
// Wait for signaled changes in a shared object.
static inline tao_status shared_object_wait_condition(
const char* func,
tao_shared_object* obj)
{
return wait_condition(func, &obj->cond, &obj->mutex);
}
// Wait for signaled changes in a shared object without blocking for longer
// than an absolute time limit.
static inline tao_status shared_object_abstimed_wait_condition(
const char* func,
tao_shared_object* obj,
const tao_time* abstime)
{
return abstimed_wait_condition(func, &obj->cond, &obj->mutex, abstime);
}
// Wait for signaled changes in a shared object without blocking for longer
// than a given number of seconds.
static inline tao_status shared_object_timed_wait_condition(
const char* func,
tao_shared_object* obj,
double secs)
{
return timed_wait_condition(func, &obj->cond, &obj->mutex, secs);
}
//-----------------------------------------------------------------------------
// READ/WRITE LOCKED OBJECTS
......@@ -389,10 +46,11 @@ static inline tao_status rwlocked_object_unlock(
const char* func,
tao_rwlocked_object* obj)
{
tao_status status = shared_object_lock(func, (tao_shared_object*)obj);
tao_status status = tao_mutex_lock(&obj->base.mutex);
if (status == TAO_OK) {
int errcode = TAO_SUCCESS;
// Object has been locked.
bool notify = false;
int errcode = TAO_SUCCESS;
if (obj->users == -1) {
// Remove the write lock and notify others.
obj->users = 0;
......@@ -407,11 +65,11 @@ static inline tao_status rwlocked_object_unlock(
errcode = (obj->users == 0 ? TAO_NOT_LOCKED : TAO_CORRUPTED);
}
if (notify) {
status = shared_object_broadcast_condition(
func, (tao_shared_object*)obj);
status = tao_condition_broadcast(&obj->base.cond);
}
if (tao_mutex_unlock(&obj->base.mutex) != TAO_OK) {
status = TAO_ERROR;
}
status = shared_object_unlock_with_status(
func, (tao_shared_object*)obj, status);
if (errcode != TAO_SUCCESS) {
tao_store_error(func, errcode);
status = TAO_ERROR;
......@@ -426,38 +84,39 @@ static inline tao_status rwlocked_object_rdlock(
const char* func,
tao_rwlocked_object* obj)
{
tao_status status = shared_object_lock(
func, (tao_shared_object*)obj);
if (status != TAO_OK) {
return status;
}
while (status == TAO_OK && ! rwlocked_object_is_readable(obj)) {
status = shared_object_wait_condition(
func, (tao_shared_object*)obj);
}
tao_status status = tao_mutex_lock(&obj->base.mutex);
if (status == TAO_OK) {
obj->users += 1;
// Object has been locked.
while (status == TAO_OK && ! rwlocked_object_is_readable(obj)) {
status = tao_condition_wait(&obj->base.cond, &obj->base.mutex);
}
if (status == TAO_OK) {
obj->users += 1;
}
if (tao_mutex_unlock(&obj->base.mutex) != TAO_OK) {
status = TAO_ERROR;
}
}
return shared_object_unlock_with_status(
func, (tao_shared_object*)obj, status);
return status;
}
static inline tao_status rwlocked_object_try_rdlock(
const char* func,
tao_rwlocked_object* obj)
{
tao_status status = shared_object_try_lock(
func, (tao_shared_object*)obj);
if (status != TAO_OK) {
return status;
}
if (rwlocked_object_is_readable(obj)) {
obj->users += 1;
} else {
status = TAO_TIMEOUT;
tao_status status = tao_mutex_try_lock(&obj->base.mutex);
if (status == TAO_OK) {
// Object has been locked.
if (rwlocked_object_is_readable(obj)) {
obj->users += 1;
} else {
status = TAO_TIMEOUT;
}
if (tao_mutex_unlock(&obj->base.mutex) != TAO_OK) {
status = TAO_ERROR;
}
}
return shared_object_unlock_with_status(
func, (tao_shared_object*)obj, status);
return status;
}
static inline tao_status rwlocked_object_abstimed_rdlock(
......@@ -465,20 +124,21 @@ static inline tao_status rwlocked_object_abstimed_rdlock(
tao_rwlocked_object* obj,
const tao_time* abstime)
{
tao_status status = shared_object_abstimed_lock(
func, (tao_shared_object*)obj, abstime);
if (status != TAO_OK) {
return status;
}
while (status == TAO_OK && ! rwlocked_object_is_readable(obj)) {
status = shared_object_abstimed_wait_condition(
func, (tao_shared_object*)obj, abstime);
}
tao_status status = tao_mutex_abstimed_lock(&obj->base.mutex, abstime);
if (status == TAO_OK) {
obj->users += 1;
// Object has been locked.
while (status == TAO_OK && ! rwlocked_object_is_readable(obj)) {
status = tao_condition_abstimed_wait(
&obj->base.cond, &obj->base.mutex, abstime);
}
if (status == TAO_OK) {
obj->users += 1;
}
if (tao_mutex_unlock(&obj->base.mutex) != TAO_OK) {
status = TAO_ERROR;
}
}
return shared_object_unlock_with_status(
func, (tao_shared_object*)obj, status);
return status;
}
static inline tao_status rwlocked_object_timed_rdlock(
......@@ -487,7 +147,7 @@ static inline tao_status rwlocked_object_timed_rdlock(
double secs)
{
tao_time abstime;
switch (get_absolute_timeout(func, &abstime, secs)) {
switch (tao_get_absolute_timeout(&abstime, secs)) {
case TAO_TIMEOUT_PAST:
return TAO_TIMEOUT;
case TAO_TIMEOUT_NOW:
......@@ -507,40 +167,41 @@ static inline tao_status rwlocked_object_wrlock(
const char* func,
tao_rwlocked_object* obj)
{
tao_status status = shared_object_lock(
func, (tao_shared_object*)obj);
if (status != TAO_OK) {
return status;
}
obj->writers += 1; // one more pending writer
while (status == TAO_OK && ! rwlocked_object_is_writable(obj)) {
status = shared_object_wait_condition(
func, (tao_shared_object*)obj);
}
obj->writers -= 1; // one less pending writer
tao_status status = tao_mutex_lock(&obj->base.mutex);
if (status == TAO_OK) {
obj->users = -1;
// Object has been locked.
obj->writers += 1; // one more pending writer
while (status == TAO_OK && ! rwlocked_object_is_writable(obj)) {
status = tao_condition_wait(&obj->base.cond, &obj->base.mutex);
}
obj->writers -= 1; // one less pending writer
if (status == TAO_OK) {
obj->users = -1;
}
if (tao_mutex_unlock(&obj->base.mutex) != TAO_OK) {
status = TAO_ERROR;
}
}
return shared_object_unlock_with_status(
func, (tao_shared_object*)obj, status);
return status;
}
static inline tao_status rwlocked_object_try_wrlock(
const char* func,
tao_rwlocked_object* obj)
{
tao_status status = shared_object_try_lock(
func, (tao_shared_object*)obj);
if (status != TAO_OK) {
return status;
}
if (rwlocked_object_is_writable(obj)) {
obj->users = -1;
} else {
status = TAO_TIMEOUT;
tao_status status = tao_mutex_try_lock(&obj->base.mutex);
if (status == TAO_OK) {
// Object has been locked.
if (rwlocked_object_is_writable(obj)) {
obj->users = -1;
} else {
status = TAO_TIMEOUT;
}
if (tao_mutex_unlock(&obj->base.mutex) != TAO_OK) {
status = TAO_ERROR;
}
}
return shared_object_unlock_with_status(
func, (tao_shared_object*)obj, status);
return status;
}
static inline tao_status rwlocked_object_abstimed_wrlock(
......@@ -548,22 +209,23 @@ static inline tao_status rwlocked_object_abstimed_wrlock(
tao_rwlocked_object* obj,
const tao_time* abstime)
{
tao_status status = shared_object_abstimed_lock(
func, (tao_shared_object*)obj, abstime);
if (status != TAO_OK) {
return status;
}
obj->writers += 1; // one more pending writer
while (status == TAO_OK && ! rwlocked_object_is_writable(obj)) {
status = shared_object_abstimed_wait_condition(
func, (tao_shared_object*)obj, abstime);
}
obj->writers -= 1; // one less pending writer
tao_status status = tao_mutex_abstimed_lock(&obj->base.mutex, abstime);
if (status == TAO_OK) {
obj->users = -1;
// Object has been locked.
obj->writers += 1; // one more pending writer
while (status == TAO_OK && ! rwlocked_object_is_writable(obj)) {
status = tao_condition_abstimed_wait(
&obj->base.cond, &obj->base.mutex, abstime);
}
obj->writers -= 1; // one less pending writer
if (status == TAO_OK) {
obj->users = -1;
}
if (tao_mutex_unlock(&obj->base.mutex) != TAO_OK) {
status = TAO_ERROR;
}
}
return shared_object_unlock_with_status(
func, (tao_shared_object*)obj, status);
return status;
}
static inline tao_status rwlocked_object_timed_wrlock(
......@@ -572,7 +234,7 @@ static inline tao_status rwlocked_object_timed_wrlock(
double secs)
{
tao_time abstime;
switch (get_absolute_timeout(func, &abstime, secs)) {
switch (tao_get_absolute_timeout(&abstime, secs)) {
case TAO_TIMEOUT_PAST:
return TAO_TIMEOUT;
case TAO_TIMEOUT_NOW:
......
......@@ -105,6 +105,7 @@ tao_shmid TAO_XJOIN3(tao_,TYPE,_get_shmid)(
#if IS_SHARED_OBJECT && !IS_RWLOCKED_OBJECT
// Unlock a shared object.
tao_status TAO_XJOIN3(tao_,TYPE,_unlock)(
TAO_XJOIN2(tao_,TYPE)* obj)
{
......@@ -112,9 +113,11 @@ tao_status TAO_XJOIN3(tao_,TYPE,_unlock)(
tao_store_error(__func__, TAO_BAD_ADDRESS);
return TAO_ERROR;
}
return shared_object_unlock(__func__, tao_shared_object_cast(obj));
return tao_mutex_unlock(
&tao_shared_object_cast(obj)->mutex);
}
// Lock a shared object.
tao_status TAO_XJOIN3(tao_,TYPE,_lock)(
TAO_XJOIN2(tao_,TYPE)* obj)
{
......@@ -122,9 +125,11 @@ tao_status TAO_XJOIN3(tao_,TYPE,_lock)(