Added support for POSIX read/write locks

parent 3dfb2d6d
......@@ -232,7 +232,7 @@ THREAD_CFLAGS=''
THREAD_LIBS=''
THREAD_GC_FLAGS='--enable-threads=posix'
INSTALL_TARGET='install'
THREAD_OBJ='threads/process threads/mutex threads/condition_variable'
THREAD_OBJ="$THREAD_OBJ threads/process threads/mutex threads/condition_variable"
clibs=''
SONAME=''
SONAME_LDFLAGS=''
......@@ -824,9 +824,20 @@ if test $ECL_WORKING_SEM_INIT = yes ; then
AC_DEFINE(ECL_SEMAPHORES)
AC_DEFINE(HAVE_SEM_INIT)
THREAD_OBJ="$THREAD_OBJ threads/semaphore"
echo $THREAD_OBJ
fi
])
dnl ----------------------------------------------------------------------
dnl Check whether we have POSIX read/write locks are available
AC_DEFUN([ECL_POSIX_RWLOCK],[
AC_CHECK_FUNC( [pthread_rwlock_init], [
AC_DEFINE(ECL_RWLOCK)
AC_DEFINE(HAVE_POSIX_RWLOCK)
THREAD_OBJ="$THREAD_OBJ threads/rwlock"
], [])
])
dnl ----------------------------------------------------------------------
dnl Check "char **environ" is available
......
......@@ -1045,6 +1045,15 @@ standard_finalizer(cl_object o)
ecl_enable_interrupts_env(the_env);
break;
}
#ifdef ECL_RWLOCK
case t_rwlock: {
const cl_env_ptr the_env = ecl_process_env();
ecl_disable_interrupts_env(the_env);
pthread_rwlock_destroy(&o->lock.mutex);
ecl_enable_interrupts_env(the_env);
break;
}
#endif
case t_condition_variable: {
const cl_env_ptr the_env = ecl_process_env();
ecl_disable_interrupts_env(the_env);
......
......@@ -34,9 +34,6 @@ ecl_def_string_array(feature_names,static,const) = {
#ifdef ECL_THREADS
ecl_def_string_array_elt("THREADS"),
#endif
#ifdef ECL_SEMAPHORES
ecl_def_string_array_elt("SEMAPHORES"),
#endif
#ifdef CLOS
ecl_def_string_array_elt("CLOS"),
#endif
......@@ -110,6 +107,12 @@ ecl_def_string_array(feature_names,static,const) = {
#endif
#ifdef ECL_SSE2
ecl_def_string_array_elt("SSE2"),
#endif
#ifdef ECL_SEMAPHORES
ecl_def_string_array_elt("SEMAPHORES"),
#endif
#ifdef ECL_RWLOCK
ecl_def_string_array_elt("ECL-READ-WRITE-LOCK"),
#endif
ecl_def_string_array_elt(0)
};
......
......@@ -1535,6 +1535,13 @@ cl_symbols[] = {
{MP_ "SEMAPHORE-SIGNAL", MP_ORDINARY, mp_semaphore_signal, 1, OBJNULL},
{MP_ "SEMAPHORE-CLOSE", MP_ORDINARY, mp_semaphore_close, 1, OBJNULL},
# endif
{MP_ "MAKE-RWLOCK", MP_ORDINARY, mp_make_rwlock, -1, OBJNULL},
{MP_ "RWLOCK", MP_ORDINARY, NULL, -1, OBJNULL},
{MP_ "RWLOCK-NAME", MP_ORDINARY, mp_rwlock_name, 1, OBJNULL},
{MP_ "GET-RWLOCK-READ", MP_ORDINARY, mp_get_rwlock_read, -1, OBJNULL},
{MP_ "GET-RWLOCK-WRITE", MP_ORDINARY, mp_get_rwlock_write, -1, OBJNULL},
{MP_ "GIVEUP-RWLOCK-READ", MP_ORDINARY, mp_giveup_rwlock_read, 1, OBJNULL},
{MP_ "GIVEUP-RWLOCK-WRITE", MP_ORDINARY, mp_giveup_rwlock_write, 1, OBJNULL},
#endif
{SYS_ "WHILE", SI_ORDINARY, NULL, -1, OBJNULL},
......
......@@ -1535,6 +1535,13 @@ cl_symbols[] = {
{MP_ "SEMAPHORE-SIGNAL","mp_semaphore_signal"},
{MP_ "SEMAPHORE-CLOSE","mp_semaphore_close"},
# endif
{MP_ "MAKE-RWLOCK","mp_make_rwlock"},
{MP_ "RWLOCK",NULL},
{MP_ "RWLOCK-NAME","mp_rwlock_name"},
{MP_ "GET-RWLOCK-READ","mp_get_rwlock_read"},
{MP_ "GET-RWLOCK-WRITE","mp_get_rwlock_write"},
{MP_ "GIVEUP-RWLOCK-READ","mp_giveup_rwlock_read"},
{MP_ "GIVEUP-RWLOCK-WRITE","mp_giveup_rwlock_write"},
#endif
{SYS_ "WHILE",NULL},
......
/* -*- mode: c; c-basic-offset: 8 -*- */
/*
rwlock.d -- POSIX read-write locks
*/
/*
Copyright (c) 2003, Juan Jose Garcia Ripoll.
ECL is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
See file '../Copyright' for full 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)
{
#ifdef ECL_WINDOWS_THREADS
FEwin32_error("When acting on rwlock ~A, got an unexpected error.", 1, lock);
#else
FEerror("When acting on rwlock ~A, got an unexpected error.", 1, lock);
#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
ecl_disable_interrupts_env(the_env);
pthread_rwlock_init(&output->rwlock.mutex, NULL);
ecl_set_finalizer_unprotected(output, Ct);
ecl_enable_interrupts_env(the_env);
#else
output->rwlock.mutex = ecl_make_lock(name, false);
#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 (type_of(lock) != t_lock)
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 (type_of(lock) != t_rwlock)
FEerror_not_a_rwlock(lock);
#ifdef ECL_RWLOCK
pthread_rwlock_unlock(&lock->rwlock.mutex);
@(return Ct)
#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 (type_of(lock) != t_rwlock)
FEerror_not_a_rwlock(lock);
#ifdef ECL_RWLOCK
{
const cl_env_ptr env = ecl_process_env();
cl_object output = Ct;
int rc = pthread_rwlock_tryrdlock(&lock->rwlock.mutex);
if (rc == 0) {
output = Ct;
} else if (rc == EBUSY) {
output = Cnil;
} else {
FEunknown_rwlock_error(lock);
}
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 (type_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);
}
ecl_return1(env, Ct);
}
#else
return mp_get_lock_wait(lock->rwlock.mutex);
#endif
}
@(defun mp::get-rwlock-read (lock &optional (wait Ct))
@
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 (type_of(lock) != t_rwlock)
FEerror_not_a_rwlock(lock);
#ifdef ECL_RWLOCK
{
const cl_env_ptr env = ecl_process_env();
cl_object output = Ct;
int rc = pthread_rwlock_tryrdlock(&lock->rwlock.mutex);
if (rc == 0) {
output = Ct;
} else if (rc == EBUSY) {
output = Cnil;
} else {
FEunknown_rwlock_error(lock);
}
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 (type_of(lock) != t_rwlock)
FEerror_not_a_rwlock(lock);
#ifdef ECL_RWLOCK
{
int rc = pthread_rwlock_rdlock(&lock->rwlock.mutex);
if (rc != 0) {
FEunknown_rwlock_error(lock);
}
@(return Ct)
}
#else
return mp_get_lock_wait(lock->rwlock.mutex);
#endif
}
@(defun mp::get-rwlock-write (lock &optional (wait Ct))
@
if (Null(wait))
return mp_get_rwlock_write_nowait(lock);
else
return mp_get_rwlock_write_wait(lock);
@)
......@@ -85,6 +85,7 @@
(si::weak-pointer)
#+threads (mp::process)
#+threads (mp::lock)
#+threads (mp::rwlock)
#+threads (mp::condition-variable)
#+semaphores (mp::semaphore)
#+sse2 (ext::sse-pack))))
......
......@@ -4610,7 +4610,7 @@ THREAD_CFLAGS=''
THREAD_LIBS=''
THREAD_GC_FLAGS='--enable-threads=posix'
INSTALL_TARGET='install'
THREAD_OBJ='threads/process threads/mutex threads/condition_variable'
THREAD_OBJ="$THREAD_OBJ threads/process threads/mutex threads/condition_variable"
clibs=''
SONAME=''
SONAME_LDFLAGS=''
......@@ -6010,36 +6010,6 @@ if test "${enable_threads}" = "yes" ; then
$as_echo "$as_me: error: Threads aren't supported on this system." >&2;}
{ (exit 1); exit 1; }; }
else
boehm_configure_flags="${boehm_configure_flags} ${THREAD_GC_FLAGS}"
for k in $THREAD_OBJ; do EXTRA_OBJS="$EXTRA_OBJS ${k}.${OBJEXT}"; done
{ $as_echo "$as_me:$LINENO: checking for thread object files" >&5
$as_echo_n "checking for thread object files... " >&6; }
{ $as_echo "$as_me:$LINENO: result: ${THREAD_OBJ}" >&5
$as_echo "${THREAD_OBJ}" >&6; }
LIBS="${THREAD_LIBS} ${LIBS}"
CFLAGS="${CFLAGS} ${THREAD_CFLAGS}"
cat >>confdefs.h <<\_ACEOF
#define ECL_THREADS 1
_ACEOF
if test "${with___thread}" = "auto"; then
with___thread=${ac_cv_ecl___thread}
fi
{ $as_echo "$as_me:$LINENO: checking for use of __thread" >&5
$as_echo_n "checking for use of __thread... " >&6; }
if test "${with___thread}" = "yes"; then
cat >>confdefs.h <<\_ACEOF
#define WITH___THREAD 1
_ACEOF
{ $as_echo "$as_me:$LINENO: result: yes" >&5
$as_echo "yes" >&6; }
else
{ $as_echo "$as_me:$LINENO: result: no" >&5
$as_echo "no" >&6; }
fi
{ $as_echo "$as_me:$LINENO: checking working sem_init()" >&5
$as_echo_n "checking working sem_init()... " >&6; }
......@@ -6117,8 +6087,140 @@ _ACEOF
_ACEOF
THREAD_OBJ="$THREAD_OBJ threads/semaphore"
echo $THREAD_OBJ
fi
{ $as_echo "$as_me:$LINENO: checking for pthread_rwlock_init" >&5
$as_echo_n "checking for pthread_rwlock_init... " >&6; }
if test "${ac_cv_func_pthread_rwlock_init+set}" = set; then
$as_echo_n "(cached) " >&6
else
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
/* Define pthread_rwlock_init to an innocuous variant, in case <limits.h> declares pthread_rwlock_init.
For example, HP-UX 11i <limits.h> declares gettimeofday. */
#define pthread_rwlock_init innocuous_pthread_rwlock_init
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char pthread_rwlock_init (); below.
Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
<limits.h> exists even on freestanding compilers. */
#ifdef __STDC__
# include <limits.h>
#else
# include <assert.h>
#endif
#undef pthread_rwlock_init
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char pthread_rwlock_init ();
/* The GNU C library defines this for functions which it implements
to always fail with ENOSYS. Some functions are actually named
something starting with __ and the normal name is an alias. */
#if defined __stub_pthread_rwlock_init || defined __stub___pthread_rwlock_init
choke me
#endif
int
main ()
{
return pthread_rwlock_init ();
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext conftest$ac_exeext
if { (ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
$as_echo "$ac_try_echo") >&5
(eval "$ac_link") 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
$as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && {
test -z "$ac_c_werror_flag" ||
test ! -s conftest.err
} && test -s conftest$ac_exeext && {
test "$cross_compiling" = yes ||
$as_test_x conftest$ac_exeext
}; then
ac_cv_func_pthread_rwlock_init=yes
else
$as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_cv_func_pthread_rwlock_init=no
fi
rm -rf conftest.dSYM
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
conftest$ac_exeext conftest.$ac_ext
fi
{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_pthread_rwlock_init" >&5
$as_echo "$ac_cv_func_pthread_rwlock_init" >&6; }
if test "x$ac_cv_func_pthread_rwlock_init" = x""yes; then
cat >>confdefs.h <<\_ACEOF
#define ECL_RWLOCK 1
_ACEOF
cat >>confdefs.h <<\_ACEOF
#define HAVE_POSIX_RWLOCK 1
_ACEOF
THREAD_OBJ="$THREAD_OBJ threads/rwlock"
fi
boehm_configure_flags="${boehm_configure_flags} ${THREAD_GC_FLAGS}"
for k in $THREAD_OBJ; do EXTRA_OBJS="$EXTRA_OBJS ${k}.${OBJEXT}"; done
{ $as_echo "$as_me:$LINENO: checking for thread object files" >&5
$as_echo_n "checking for thread object files... " >&6; }
{ $as_echo "$as_me:$LINENO: result: ${THREAD_OBJ}" >&5
$as_echo "${THREAD_OBJ}" >&6; }
LIBS="${THREAD_LIBS} ${LIBS}"
CFLAGS="${CFLAGS} ${THREAD_CFLAGS}"
cat >>confdefs.h <<\_ACEOF
#define ECL_THREADS 1
_ACEOF
if test "${with___thread}" = "auto"; then
with___thread=${ac_cv_ecl___thread}
fi
{ $as_echo "$as_me:$LINENO: checking for use of __thread" >&5
$as_echo_n "checking for use of __thread... " >&6; }
if test "${with___thread}" = "yes"; then
cat >>confdefs.h <<\_ACEOF
#define WITH___THREAD 1
_ACEOF
{ $as_echo "$as_me:$LINENO: result: yes" >&5
$as_echo "yes" >&6; }
else
{ $as_echo "$as_me:$LINENO: result: no" >&5
$as_echo "no" >&6; }
fi
fi
else
boehm_configure_flags="${boehm_configure_flags} --disable-threads"
......
......@@ -477,6 +477,8 @@ if test "${enable_threads}" = "yes" ; then
if test -z "${THREAD_OBJ}"; then
AC_MSG_ERROR([Threads aren't supported on this system.])
else
ECL_POSIX_SEMAPHORES
ECL_POSIX_RWLOCK
boehm_configure_flags="${boehm_configure_flags} ${THREAD_GC_FLAGS}"
for k in $THREAD_OBJ; do EXTRA_OBJS="$EXTRA_OBJS ${k}.${OBJEXT}"; done
AC_MSG_CHECKING([for thread object files])
......@@ -494,7 +496,6 @@ if test "${enable_threads}" = "yes" ; then
else
AC_MSG_RESULT([no])
fi
ECL_POSIX_SEMAPHORES
fi
else
boehm_configure_flags="${boehm_configure_flags} --disable-threads"
......
......@@ -67,6 +67,7 @@
# define ECL_WINDOWS_THREADS
# endif
/* # udef ECL_SEMAPHORES */
#undef ECL_RWLOCK
#endif
/* __thread thread-local variables? */
......@@ -399,6 +400,8 @@ typedef unsigned @CL_FIXNUM_TYPE@ cl_hashkey;
#undef HAVE_SEMAPHORE_H
/* whether we have a working sem_init() */
#undef HAVE_SEM_INIT
/* whether we have read/write locks */
#undef HAVE_POSIX_RWLOCK
/* uname() for system identification */
#undef HAVE_UNAME
#undef HAVE_UNISTD_H
......
......@@ -1740,6 +1740,17 @@ extern ECL_API cl_object mp_get_lock_nowait(cl_object lock);
extern ECL_API cl_object mp_giveup_lock(cl_object lock);
extern ECL_API cl_object ecl_make_lock(cl_object lock, bool recursive);
/* threads/rwlock.d */
extern ECL_API cl_object mp_make_rwlock _ARGS((cl_narg narg, ...));
extern ECL_API cl_object mp_rwlock_name(cl_object lock);
extern ECL_API cl_object mp_get_rwlock_read _ARGS((cl_narg narg, cl_object lock, ...));
extern ECL_API cl_object mp_get_rwlock_write _ARGS((cl_narg narg, cl_object lock, ...));
extern ECL_API cl_object mp_giveup_rwlock_read(cl_object lock);
extern ECL_API cl_object mp_giveup_rwlock_write(cl_object lock);
extern ECL_API cl_object ecl_make_rwlock(cl_object lock);
#endif /* ECL_THREADS */
/* time.c */
......
......@@ -78,6 +78,7 @@ typedef enum {
#ifdef ECL_THREADS
t_process,
t_lock,
t_rwlock,
t_condition_variable,
# ifdef ECL_SEMAPHORES
t_semaphore,
......@@ -921,6 +922,16 @@ struct ecl_lock {
pthread_mutex_t mutex;
};
struct ecl_rwlock {
HEADER;
cl_object name;
#ifdef ECL_RWLOCK
pthread_rwlock_t mutex;
#else
cl_object mutex;
#endif
};
struct ecl_condition_variable {
HEADER;
pthread_cond_t cv;
......@@ -1031,6 +1042,7 @@ union cl_lispunion {
#ifdef ECL_THREADS
struct ecl_process process; /* process */
struct ecl_lock lock; /* lock */
struct ecl_rwlock rwlock; /* read/write lock */
struct ecl_condition_variable condition_variable; /* condition-variable */
#endif
#ifdef ECL_SEMAPHORES
......
......@@ -1222,6 +1222,7 @@ if not possible."
(READTABLE)
#+threads (MP::PROCESS)
#+threads (MP::LOCK)
#+threads (MP::RWLOCK)
#+ffi (FOREIGN-DATA)
#+sse2 (EXT:SSE-PACK (OR EXT:INT-SSE-PACK
EXT:FLOAT-SSE-PACK
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment