📄 lock-impl.c
字号:
/* * lock-impl.c - pthread-based LockInterface implementation (Posix style) * * Copyright (c) 1998 * Transvirtual Technologies, Inc. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file. */#include "config.h"#include "config-std.h"#include "lerrno.h"#include "debug.h"#include "jthread.h"/* For NOTIMEOUT */#include "jsyscall.h"#ifdef KAFFE_BOEHM_GC#include "boehm-gc/boehm/include/gc.h"#endif#include <signal.h>static voidsetBlockState(jthread_t cur, unsigned int newState, void *sp, sigset_t *old_mask){ int suspendSig; sigset_t suspendMask, pendingMask; suspendSig = KaffePThread_getSuspendSignal(); sigemptyset(&suspendMask); sigaddset(&suspendMask, suspendSig); pthread_sigmask(SIG_BLOCK, &suspendMask, old_mask); pthread_mutex_lock(&cur->suspendLock); cur->blockState |= newState; cur->stackCur = sp; pthread_mutex_unlock(&cur->suspendLock); /* This thread is protected against suspendall. So if a signal has been * received it is just before the mutex_lock and after pthread_sigmask. * We must acknowledge and go in WaitForResume. */ sigpending(&pendingMask); if (sigismember(&pendingMask, suspendSig)) { KaffePThread_AckAndWaitForResume(cur, newState); }}void KaffePThread_setBlockingCall(void *sigdata){ jthread_t cur = jthread_current(); setBlockState(cur, BS_SYSCALL, (void*)&cur, (sigset_t*)sigdata);}static inline voidclearBlockState(jthread_t cur, unsigned int newState, sigset_t *old_mask){ pthread_mutex_lock(&cur->suspendLock); cur->blockState &= ~newState; if (cur->suspendState == SS_SUSPENDED) { DBG(JTHREADDETAIL, dprintf("Changing blockstate of %p to %d while in suspend, block again\n", cur, newState)); KaffePThread_WaitForResume(true, 0); } else { cur->stackCur = NULL; pthread_mutex_unlock(&cur->suspendLock); } /* Catch an interrupt event sent while we were being killed. * This is needed for Darwin's pthreads. */ if (cur->status == THREAD_KILL && ((cur->blockState & BS_THREAD) == 0)) { /* Mark the thread as inactive now to acknowledge the shutdown. */ cur->active = 0; pthread_exit(NULL); } pthread_sigmask(SIG_SETMASK, old_mask, NULL); /* Here the state is not SS_PENDING_SUSPEND so releasing the signal will * not trigger a deadlock. */}void KaffePThread_clearBlockingCall(void *sigdata){ jthread_t cur = jthread_current(); clearBlockState(cur, BS_SYSCALL, (sigset_t *)sigdata);}voidjmutex_lock(jmutex* lk ){ jthread_t cur = jthread_current (); sigset_t oldmask; setBlockState(cur, BS_MUTEX, (void*)&cur, &oldmask); pthread_mutex_lock( lk ); clearBlockState(cur, BS_MUTEX, &oldmask);}static inline intThreadCondWait(jthread_t cur, jcondvar *cv, jmutex *mux){ int status = 0; sigset_t oldmask; setBlockState(cur, BS_CV, (void*)&status, &oldmask); status = pthread_cond_wait( cv, mux ); clearBlockState(cur, BS_CV, &oldmask); return status;}/* * Wait on the condvar with a given relative timeout in ms (which we * have to convert into a absolute timespec now) */jbooleanjcondvar_wait (jcondvar* cv, jmutex *mux, jlong timeout ){ jthread_t cur = jthread_current(); int status = 0; /* * If a thread trying to get a heavy lock is interrupted, we may get here * with the interrupted flag set (because the thread didn't get the heavy * lock and has to wait again). Therefore, we must not clear the interrupted * flag here. */ if ( timeout == NOTIMEOUT ) { /* we handle this as "wait forever" */ status = ThreadCondWait(cur, cv, mux); } else { sigset_t oldmask; struct timespec abst; struct timeval now; /* timeout is in millisecs, timeval in microsecs, and timespec in nanosecs */ gettimeofday( &now, NULL); abst.tv_sec = now.tv_sec + (timeout / 1000); if( abst.tv_sec < now.tv_sec ) { /* huge timeout value, we handle this as "wait forever" */ status = ThreadCondWait(cur, cv, mux); } else { abst.tv_nsec = (now.tv_usec * 1000) + (timeout % 1000) * 1000000; if (abst.tv_nsec > 1000000000) { abst.tv_sec += 1; abst.tv_nsec -= 1000000000; } setBlockState(cur, BS_CV_TO, (void*)&status, &oldmask); status = pthread_cond_timedwait( cv, mux, &abst); clearBlockState(cur, BS_CV_TO, &oldmask); } } /* * Since we interrupt a thread blocked on a condition variable by signaling that * condition variable, we cannot set the interrupted flag based on the value of * 'signal'. Therefore, we have to rely on the interrupting thread to set the * flag. */ return (status == 0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -