sync_md.c
来自「This is a resource based on j2me embedde」· C语言 代码 · 共 564 行 · 第 1/2 页
C
564 行
/* * @(#)sync_md.c 1.32 06/10/10 * * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. * */#include "javavm/include/porting/sync.h"#include "javavm/include/porting/threads.h"#include "javavm/include/porting/float.h" /* for setFPMode() */#include <pthread.h>#include <sys/time.h>#include <errno.h>#include <signal.h>#include <unistd.h>#include <assert.h>#include <stdio.h>#include <sys/types.h>#include <sys/wait.h>#ifdef CVM_JVMPI#include "javavm/include/globals.h"#endif#ifdef CVM_JVMTI#include "javavm/include/globals.h"#include "javavm/include/jvmtiExport.h"#endif#ifdef CVM_JIT#include "javavm/include/porting/jit/jit.h"#endif/* * signal handler for CVMthreadSuspend() and CVMthreadResume() request. *//* NOTE: handleSuspendResume() is needed regardless of whether we enable thread suspension or not. This is because the IO system uses SIGUSR1 to break a blocked thread out of its wait if the corresponding file descriptor is closed. All the signal handler has to do in those cases is return. In the event that thread suspension is enabled, a SIGUSR1 from an IO function will cause the handler to be called, but since the handler always check the current suspension state self->isSuspended, receiving these SIGUSR1s won't change the behavior of suspension code. This is as we expect it to be.*/static void handleSuspendResume(int sig){#ifdef CVM_THREAD_SUSPENSION CVMThreadID *self = CVMthreadSelf(); assert(POSIX_COOKIE(self) == pthread_self()); /* NOTE: Normally, the SIGUSR1 signal would be masked out while we're in this handler thereby preventing this handler function from being called recursively. However, the sigsuspend() call below is designed to suspend this thread while re-enabling SIGUSR1 so that we can wake up if someone sends us that signal again (usually to resume the thread). Hence, it is possible to enter this handler recursively when we're waiting for sigsuspend() to return. The isInSuspendHandler flag is used to ensure that we don't do anything when the SIGUSR1 signal triggers again. We simply return. When SIGUSR1 is received again, sigsuspend() will return to its caller, thereby allowing the first invocation of this handler function to continue running again. Because there can be racing suspend and resume requests, we need to always check the isSuspended flag before returning. If the isSuspended flag is set, then we need to call sigsuspend() again to suspend the thread. The suspend/resume semantics is that the last most request will be honored. */ if (self->isInSuspendHandler) { /* The handler is already on the stack. Just return and let the first invocation of the handler deal with any changes to the suspension state which may need to be done. */ return; } if (self->isMutexBlocked || self->isWaitBlocked) { /* We're currently in the process of acquiring a mutex or is waiting on a condvar. There's nothing to do but return. When we're done acquiring the mutex or waiting on the condvar, the thread will suspend itself automatically by raising this signal. */ return; } self->isInSuspendHandler = CVM_TRUE; if (self->isSuspended) { sigset_t sig_set; pthread_sigmask(SIG_SETMASK, NULL, &sig_set); sigdelset(&sig_set, SIGUSR1); /* We'll keep suspending the thread as long as the its isSuspended flag indicates that we're supposed to be suspended. */ do { /* wait for thread resume or set-owner request */ /* Mask out other signals but allow SIGUSR1 to trigger. sigsuspend() will wait until we receive SIGUSR1 again. See NOTE above for more details. */ sigsuspend(&sig_set); } while (self->isSuspended); } self->isInSuspendHandler = CVM_FALSE;#endif /* CVM_THREAD_SUSPENSION */}#ifdef CVM_THREAD_SUSPENSION/* Purpose: Suspend the self thread. */static void suspendSelf(void){ sigset_t sig_set; /* Create the signal set for SIGUSR1: */ sigemptyset(&sig_set); sigaddset(&sig_set, SIGUSR1); /* NOTE: Prevent SIGUSR1 from triggering the signal handler while we're calling it. We need to block SIGUSR1 while we're calling the signal handler explicitly and cannot simply rely on the isInSuspendHandler flag instead because there can be a race condition that can result in resume failing. If we don't block the signal before calling handleSuspendResume(), then we could be in a suspended state (i.e. self->isSuspended is true) and just get past the check for self->isSuspended in handleSuspendResume() when a SIGUSR1 signal fires to resume the thread. The signal causes handleSuspendResume() to be called recursedly, but it does nothing because self->isSuspended is now false. The signal handler returns to mainline code which is still executing in handleSuspendResume() which proceeds to call sigsuspend() even though the thread should now be in a resumed state. This causes the thread to block even though it should not be. If we block the signal before calling handleSuspendResume(), then the signal would not trigger the recursion into handleSuspendResume(). Instead, the signal will be pending until SIGUSR1 gets unblocked by the call to sigsuspend() in handleSuspendResume(). At which point, handleSuspendResume() will be recursed into, and does nothing as expected because self->isSuspended is now false. But upon returning from the signal handler, in mainline code, we'll also return from the call to sigsuspend() and the self->isSuspended flag will be checked once more and found to be false causing handleSuspendResume() to return. Hence, the thread won't be blocking when it should have been resumed as expected. */ pthread_sigmask(SIG_BLOCK, &sig_set, NULL); /* Call the signal handler to suspend self if necessary: */ handleSuspendResume(SIGUSR1); /* Allow SIGUSR1 to trigger the signal handler again: */ pthread_sigmask(SIG_UNBLOCK, &sig_set, NULL);}/* Purpose: Locks the mutex. This version is only needed to work around issues that pthread library semantics that poses a problem for mutex locking in the face of thread suspension. Without thread suspension, we can call the POSIX mutex lock directly. */void CVMmutexLock(CVMMutex *m){ CVMThreadID * self = CVMthreadSelf(); /* The CVMThreadID may be NULL if the current thread hasn't been attached to a Java thread yet. If that is the case, we don't have to worry about suspension, and just call through to the POSIX mutex lock. This is because we will need a non-NULL CVMThreadID in order to call the suspension API. */ if (self != NULL) { /* NOTE: We're about to attempt to acquire the mutex. This can cause this thread to block on that mutex. This is OK, except that we need to let the suspend handler know so that this thread doesn't actually get suspended while it is in that state. Usually, the suspension requester thread would first acquire the mutex to make sure that the target thread doesn't get suspended while holding that mutex. But if the target thread is blocked on the mutex and gets suspended, when the owner of the mutex releases it, ownership will inadvertantly be assigned to this thread even though it is suspended (according to pthread library semantics). So the following code is put in place to ensure that the mutex is not acquired while the thread is supposed to be suspended. */ while(1) { self->isMutexBlocked = CVM_TRUE; POSIXmutexLock(&(m)->pmtx); self->isMutexBlocked = CVM_FALSE; if (self->isSuspended) { /* Oops, this thread has been given ownership of the mutex while it's supposed to be suspended. Release the mutex and suspend the thread. We can acquire the mutex again later. */ POSIXmutexUnlock(&(m)->pmtx); suspendSelf(); } else { break; } } } else { POSIXmutexLock(&(m)->pmtx); }}#endif /* CVM_THREAD_SUSPENSION */voidCVMmutexSetOwner(CVMThreadID *self, CVMMutex *m, CVMThreadID *target){ /* This is dependent on the pthreads library implementation. A private API would be preferable */ m->pmtx = target->locked; assert(!CVMmutexTryLock(m));}static voidenqueue(CVMCondVar *c, CVMThreadID *t){ *c->last_p = t; t->prev_p = c->last_p; c->last_p = &t->next; t->next = NULL;}static CVMThreadID *dequeue(CVMCondVar *c){ CVMThreadID *t = c->waiters; if (t != NULL) { c->waiters = t->next; if (t->next != NULL) { t->next->prev_p = t->prev_p; } if (c->last_p == &t->next) { assert(t->prev_p == &c->waiters); c->last_p = &c->waiters; } t->next = NULL; t->prev_p = NULL; } return t;}static voiddequeue_me(CVMCondVar *c, CVMThreadID *t){ *t->prev_p = t->next; if (t->next != NULL) { t->next->prev_p = t->prev_p; } if (c->last_p == &t->next) { c->last_p = t->prev_p; } t->next = NULL; t->prev_p = NULL;}CVMBoolCVMcondvarWait(CVMCondVar* c, CVMMutex* m, CVMJavaLong millis){ CVMBool waitForever; CVMThreadID * self = CVMthreadSelf(); struct timespec timeout; /* Determine the duration to wait: */ if (millis == 0LL) { waitForever = CVM_TRUE; } else { struct timeval tv;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?