mirror of
https://gitlab.com/embeddable-common-lisp/ecl.git
synced 2026-03-15 17:30:37 -07:00
225 lines
4.9 KiB
C
225 lines
4.9 KiB
C
/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
|
/* vim: set filetype=c tabstop=2 shiftwidth=2 expandtab: */
|
|
|
|
/*
|
|
* rwlock.d - POSIX read-write locks
|
|
*
|
|
* Copyright (c) 2003 Juan Jose Garcia Ripoll
|
|
*
|
|
* See file 'LICENSE' for the copyright details.
|
|
*
|
|
*/
|
|
|
|
#ifndef __sun__ /* See unixinit.d for this */
|
|
#define _XOPEN_SOURCE 600 /* For pthread mutex attributes */
|
|
#endif
|
|
#include <errno.h>
|
|
#include <ecl/ecl.h>
|
|
#ifdef ECL_WINDOWS_THREADS
|
|
# include <windows.h>
|
|
#else
|
|
# include <pthread.h>
|
|
#endif
|
|
#include <ecl/internal.h>
|
|
|
|
/*----------------------------------------------------------------------
|
|
* READ/WRITE LOCKS
|
|
*/
|
|
|
|
static void
|
|
FEerror_not_a_rwlock(cl_object lock)
|
|
{
|
|
FEwrong_type_argument(@'mp::rwlock', lock);
|
|
}
|
|
|
|
static void
|
|
FEunknown_rwlock_error(cl_object lock, int rc)
|
|
{
|
|
#ifdef ECL_WINDOWS_THREADS
|
|
FEwin32_error("When acting on rwlock ~A, got an unexpected error.", 1, lock);
|
|
#else
|
|
const char *msg = NULL;
|
|
switch (rc) {
|
|
case EINVAL:
|
|
msg = "The value specified by rwlock is invalid";
|
|
break;
|
|
case EPERM:
|
|
msg = "Read/write lock not owned by us";
|
|
break;
|
|
case EDEADLK:
|
|
msg = "Thread already owns this lock";
|
|
break;
|
|
case ENOMEM:
|
|
msg = "Out of memory";
|
|
break;
|
|
default:
|
|
FElibc_error("When acting on rwlock ~A, got an unexpected error.",
|
|
1, lock);
|
|
}
|
|
FEerror("When acting on rwlock ~A, got the following C library error:~%"
|
|
"~A", 2, lock, make_constant_base_string(msg));
|
|
#endif
|
|
}
|
|
|
|
cl_object
|
|
ecl_make_rwlock(cl_object name)
|
|
{
|
|
const cl_env_ptr the_env = ecl_process_env();
|
|
cl_object output = ecl_alloc_object(t_rwlock);
|
|
#ifdef ECL_RWLOCK
|
|
int rc;
|
|
ecl_disable_interrupts_env(the_env);
|
|
rc = pthread_rwlock_init(&output->rwlock.mutex, NULL);
|
|
ecl_enable_interrupts_env(the_env);
|
|
if (rc) {
|
|
FEerror("Unable to create read/write lock", 0);
|
|
}
|
|
ecl_set_finalizer_unprotected(output, ECL_T);
|
|
#else
|
|
output->rwlock.mutex = ecl_make_lock(name, 0);
|
|
#endif
|
|
output->rwlock.name = name;
|
|
return output;
|
|
}
|
|
|
|
@(defun mp::make-rwlock (&key name)
|
|
@
|
|
@(return ecl_make_rwlock(name));
|
|
@)
|
|
|
|
cl_object
|
|
mp_rwlock_name(cl_object lock)
|
|
{
|
|
const cl_env_ptr env = ecl_process_env();
|
|
if (ecl_t_of(lock) != t_rwlock)
|
|
FEerror_not_a_rwlock(lock);
|
|
ecl_return1(env, lock->rwlock.name);
|
|
}
|
|
|
|
cl_object
|
|
mp_giveup_rwlock_read(cl_object lock)
|
|
{
|
|
/* Must be called with interrupts disabled. */
|
|
if (ecl_t_of(lock) != t_rwlock)
|
|
FEerror_not_a_rwlock(lock);
|
|
#ifdef ECL_RWLOCK
|
|
{
|
|
int rc = pthread_rwlock_unlock(&lock->rwlock.mutex);
|
|
if (rc)
|
|
FEunknown_rwlock_error(lock, rc);
|
|
@(return ECL_T);
|
|
}
|
|
#else
|
|
return mp_giveup_lock(lock->rwlock.mutex);
|
|
#endif
|
|
}
|
|
|
|
cl_object
|
|
mp_giveup_rwlock_write(cl_object lock)
|
|
{
|
|
return mp_giveup_rwlock_read(lock);
|
|
}
|
|
|
|
cl_object
|
|
mp_get_rwlock_read_nowait(cl_object lock)
|
|
{
|
|
if (ecl_t_of(lock) != t_rwlock)
|
|
FEerror_not_a_rwlock(lock);
|
|
#ifdef ECL_RWLOCK
|
|
{
|
|
const cl_env_ptr env = ecl_process_env();
|
|
cl_object output = ECL_T;
|
|
int rc = pthread_rwlock_tryrdlock(&lock->rwlock.mutex);
|
|
if (rc == 0) {
|
|
output = ECL_T;
|
|
} else if (rc == EBUSY) {
|
|
output = ECL_NIL;
|
|
} else {
|
|
FEunknown_rwlock_error(lock, rc);
|
|
}
|
|
ecl_return1(env, output);
|
|
}
|
|
#else
|
|
return mp_get_lock_nowait(lock->rwlock.mutex);
|
|
#endif
|
|
}
|
|
|
|
cl_object
|
|
mp_get_rwlock_read_wait(cl_object lock)
|
|
{
|
|
if (ecl_t_of(lock) != t_rwlock)
|
|
FEerror_not_a_rwlock(lock);
|
|
#ifdef ECL_RWLOCK
|
|
{
|
|
const cl_env_ptr env = ecl_process_env();
|
|
int rc = pthread_rwlock_rdlock(&lock->rwlock.mutex);
|
|
if (rc != 0) {
|
|
FEunknown_rwlock_error(lock, rc);
|
|
}
|
|
ecl_return1(env, ECL_T);
|
|
}
|
|
#else
|
|
return mp_get_lock_wait(lock->rwlock.mutex);
|
|
#endif
|
|
}
|
|
|
|
@(defun mp::get-rwlock-read (lock &optional (wait ECL_T))
|
|
@
|
|
if (Null(wait))
|
|
return mp_get_rwlock_read_nowait(lock);
|
|
else
|
|
return mp_get_rwlock_read_wait(lock);
|
|
@)
|
|
|
|
cl_object
|
|
mp_get_rwlock_write_nowait(cl_object lock)
|
|
{
|
|
if (ecl_t_of(lock) != t_rwlock)
|
|
FEerror_not_a_rwlock(lock);
|
|
#ifdef ECL_RWLOCK
|
|
{
|
|
const cl_env_ptr env = ecl_process_env();
|
|
cl_object output = ECL_T;
|
|
int rc = pthread_rwlock_trywrlock(&lock->rwlock.mutex);
|
|
if (rc == 0) {
|
|
output = ECL_T;
|
|
} else if (rc == EBUSY) {
|
|
output = ECL_NIL;
|
|
} else {
|
|
FEunknown_rwlock_error(lock, rc);
|
|
}
|
|
ecl_return1(env, output);
|
|
}
|
|
#else
|
|
return mp_get_lock_nowait(lock->rwlock.mutex);
|
|
#endif
|
|
}
|
|
|
|
cl_object
|
|
mp_get_rwlock_write_wait(cl_object lock)
|
|
{
|
|
cl_env_ptr env = ecl_process_env();
|
|
if (ecl_t_of(lock) != t_rwlock)
|
|
FEerror_not_a_rwlock(lock);
|
|
#ifdef ECL_RWLOCK
|
|
{
|
|
int rc = pthread_rwlock_wrlock(&lock->rwlock.mutex);
|
|
if (rc != 0) {
|
|
FEunknown_rwlock_error(lock, rc);
|
|
}
|
|
@(return ECL_T);
|
|
}
|
|
#else
|
|
return mp_get_lock_wait(lock->rwlock.mutex);
|
|
#endif
|
|
}
|
|
|
|
@(defun mp::get-rwlock-write (lock &optional (wait ECL_T))
|
|
@
|
|
if (Null(wait)) {
|
|
return mp_get_rwlock_write_nowait(lock);
|
|
}
|
|
else {
|
|
return mp_get_rwlock_write_wait(lock);
|
|
}
|
|
@)
|