#include <commonp.h>
#if defined(RPC_MUTEX_DEBUG) || defined(RPC_MUTEX_STATS)
PRIVATE dcethread* rpc_g_null_thread_handle;
#define NULL_THREAD rpc_g_null_thread_handle
#define IS_MY_THREAD(t) dcethread_equal((t), my_thread)
INTERNAL rpc_mutex_stats_t mutex_stats = {0};
INTERNAL rpc_cond_stats_t cond_stats = {0};
PRIVATE boolean rpc__mutex_init
(
rpc_mutex_p_t mp
)
{
mp->stats.busy = 0;
mp->stats.lock = 0;
mp->stats.try_lock = 0;
mp->stats.unlock = 0;
mp->stats.init = 1;
mp->stats.deletes = 0;
mp->stats.lock_assert = 0;
mp->stats.unlock_assert = 0;
mp->is_locked = false;
mp->owner = NULL_THREAD;
mp->locker_file = "never_locked";
mp->locker_line = 0;
if (dcethread_mutex_init(&mp->m, NULL) != 0) {
return (false);
}
mutex_stats.init++;
return(true);
}
PRIVATE boolean rpc__mutex_delete
(
rpc_mutex_p_t mp
)
{
mp->stats.deletes++;
mutex_stats.deletes++;
dcethread_mutex_destroy(&mp->m);
return(true);
}
PRIVATE boolean rpc__mutex_lock
(
rpc_mutex_p_t mp,
char *file,
int line
)
{
dcethread* my_thread = NULL_THREAD;
boolean is_locked = mp->is_locked;
boolean dbg;
dbg = RPC_DBG(rpc_es_dbg_mutex, 5);
if (dbg)
{
my_thread = dcethread_self();
if (is_locked && IS_MY_THREAD(mp->owner))
{
RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1,
("(rpc__mutex_lock) deadlock with self at %s/%d (previous lock at %s/%d)\n",
file, line, mp->locker_file, mp->locker_line));
return(false);
}
}
dcethread_mutex_lock(&mp->m);
mp->is_locked = true;
if (dbg)
{
mp->owner = my_thread;
mp->locker_file = file;
mp->locker_line = line;
}
if (is_locked)
{
mp->stats.busy++;
mutex_stats.busy++;
}
mp->stats.lock++;
mutex_stats.lock++;
return(true);
}
PRIVATE boolean rpc__mutex_try_lock
(
rpc_mutex_p_t mp,
boolean *bp,
char *file,
int line
)
{
dcethread* my_thread = NULL_THREAD;
boolean is_locked = mp->is_locked;
boolean dbg;
dbg = RPC_DBG(rpc_es_dbg_mutex, 5);
if (dbg)
{
my_thread = dcethread_self();
if (is_locked && IS_MY_THREAD(mp->owner))
{
RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1,
("(rpc__mutex_try_lock) deadlock with self at %s/%d (previous lock at %s/%d)\n",
file, line, mp->locker_file, mp->locker_line));
return(false);
}
}
*bp = dcethread_mutex_trylock(&mp->m);
if (*bp)
{
mp->is_locked = true;
if (dbg)
{
mp->owner = my_thread;
mp->locker_file = file;
mp->locker_line = line;
}
}
else
{
mp->stats.busy++;
mutex_stats.busy++;
}
mp->stats.try_lock++;
mutex_stats.try_lock++;
return(true);
}
PRIVATE boolean rpc__mutex_unlock
(
rpc_mutex_p_t mp
)
{
dcethread* my_thread;
boolean is_locked = mp->is_locked;
boolean dbg;
dbg = RPC_DBG(rpc_es_dbg_mutex, 5);
if (dbg)
{
if (! is_locked)
{
RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1,
("(rpc__mutex_unlock) not locked\n"));
return(false);
}
my_thread = dcethread_self();
if (!IS_MY_THREAD(mp->owner))
{
RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1,
("(rpc__mutex_unlock) not owner (owner at %s/%d)\n",
mp->locker_file, mp->locker_line));
return(false);
}
mp->owner = NULL_THREAD;
}
mp->stats.unlock++;
mutex_stats.unlock++;
mp->is_locked = false;
dcethread_mutex_unlock(&mp->m);
return(true);
}
PRIVATE boolean rpc__mutex_lock_assert
(
rpc_mutex_p_t mp
)
{
dcethread* my_thread;
boolean is_locked = mp->is_locked;
boolean dbg;
dbg = RPC_DBG(rpc_es_dbg_mutex, 5);
mp->stats.lock_assert++;
mutex_stats.lock_assert++;
if (dbg)
{
if (! is_locked)
{
RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1,
("(rpc__mutex_lock_assert) not locked\n"));
return(false);
}
my_thread = dcethread_self();
if (!IS_MY_THREAD(mp->owner))
{
RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1,
("(rpc__mutex_lock_assert) not owner\n"));
return(false);
}
}
return(true);
}
PRIVATE boolean rpc__mutex_unlock_assert
(
rpc_mutex_p_t mp
)
{
dcethread* my_thread;
boolean is_locked = mp->is_locked;
boolean dbg;
dbg = RPC_DBG(rpc_es_dbg_mutex, 5);
mp->stats.unlock_assert++;
mutex_stats.unlock_assert++;
if (dbg)
{
if (! is_locked)
return(true);
my_thread = dcethread_self();
if (IS_MY_THREAD(mp->owner))
{
RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1,
("(rpc__mutex_unlock_assert) owner\n"));
return(false);
}
}
return(true);
}
boolean rpc__cond_init
(
rpc_cond_p_t cp,
rpc_mutex_p_t mp
)
{
cp->stats.init = 1;
cp->stats.deletes = 0;
cp->stats.wait = 0;
cp->stats.signals = 0;
cp->mp = mp;
dcethread_cond_init(&cp->c, NULL);
cond_stats.init++;
return(true);
}
boolean rpc__cond_delete
(
rpc_cond_p_t cp,
rpc_mutex_p_t mp ATTRIBUTE_UNUSED
)
{
cp->stats.deletes++;
cond_stats.deletes++;
dcethread_cond_destroy(&cp->c);
return(true);
}
boolean rpc__cond_wait
(
rpc_cond_p_t cp,
rpc_mutex_p_t mp,
char *file,
int line
)
{
dcethread* my_thread;
volatile boolean dbg;
DO_NOT_CLOBBER(my_thread);
cp->stats.wait++;
cond_stats.wait++;
dbg = RPC_DBG(rpc_es_dbg_mutex, 5);
if (dbg)
{
if (! rpc__mutex_lock_assert(mp))
{
RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1,
("(rpc__cond_wait) mutex usage error\n"));
return(false);
}
if (cp->mp != mp)
{
RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1,
("(rpc__cond_wait) incorrect mutex\n"));
return(false);
}
my_thread = dcethread_self();
mp->owner = NULL_THREAD;
}
mp->is_locked = false;
TRY
dcethread_cond_wait_throw(&cp->c, &mp->m);
CATCH_ALL
mp->is_locked = true;
if (dbg)
{
mp->owner = my_thread;
mp->locker_file = file;
mp->locker_line = line;
}
RERAISE;
ENDTRY
mp->is_locked = true;
if (dbg)
{
mp->owner = my_thread;
mp->locker_file = file;
mp->locker_line = line;
}
return(true);
}
boolean rpc__cond_timed_wait
(
rpc_cond_p_t cp,
rpc_mutex_p_t mp,
struct timespec *wtime,
char *file,
int line
)
{
dcethread* my_thread;
volatile boolean dbg;
DO_NOT_CLOBBER(my_thread);
cp->stats.wait++;
cond_stats.wait++;
dbg = RPC_DBG(rpc_es_dbg_mutex, 5);
if (dbg)
{
if (! rpc__mutex_lock_assert(mp))
{
RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1,
("(rpc__cond_wait) mutex usage error\n"));
return(false);
}
if (cp->mp != mp)
{
RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1,
("(rpc__cond_wait) incorrect mutex\n"));
return(false);
}
my_thread = dcethread_self();
mp->owner = NULL_THREAD;
}
mp->is_locked = false;
TRY {
dcethread_cond_timedwait_throw(&cp->c, &mp->m, wtime);
}
CATCH_ALL
mp->is_locked = true;
if (dbg)
{
mp->owner = my_thread;
mp->locker_file = file;
mp->locker_line = line;
}
RERAISE;
ENDTRY
mp->is_locked = true;
if (dbg)
{
mp->owner = my_thread;
mp->locker_file = file;
mp->locker_line = line;
}
return(true);
}
boolean rpc__cond_signal
(
rpc_cond_p_t cp,
rpc_mutex_p_t mp ATTRIBUTE_UNUSED
)
{
cp->stats.signals++;
cond_stats.signals++;
dcethread_cond_signal(&cp->c);
return(true);
}
boolean rpc__cond_broadcast
(
rpc_cond_p_t cp,
rpc_mutex_p_t mp ATTRIBUTE_UNUSED
)
{
cp->stats.signals++;
cond_stats.signals++;
dcethread_cond_broadcast(&cp->c);
return(true);
}
#else
#ifdef MIREK_NOT_DEFINED
INTERNAL void rpc__mutex_none (void)
{
}
#endif
#endif