/* Lock a mutex */ PUBLIC void mprSpinLock(MprSpin *lock) { if (lock == 0) return; #if ME_DEBUG /* Spin locks don't support recursive locking on all operating systems. */ assert(lock->owner != mprGetCurrentOsThread()); #endif #if USE_MPR_LOCK mprTryLock(&lock->cs); #elif MACOSX OSSpinLockLock(&lock->cs); #elif ME_UNIX_LIKE && ME_COMPILER_HAS_SPINLOCK pthread_spin_lock(&lock->cs); #elif ME_UNIX_LIKE pthread_mutex_lock(&lock->cs); #elif ME_WIN_LIKE if (!lock->freed) { EnterCriticalSection(&lock->cs); } #elif VXWORKS semTake(lock->cs, WAIT_FOREVER); #endif #if ME_DEBUG assert(lock->owner != mprGetCurrentOsThread()); lock->owner = mprGetCurrentOsThread(); #endif }
/* Try to attain a lock. Do not block! Returns true if the lock was attained. */ PUBLIC bool mprTrySpinLock(MprSpin *lock) { int rc; if (lock == 0) return 0; #if USE_MPR_LOCK mprTryLock(&lock->cs); #elif MACOSX rc = !OSSpinLockTry(&lock->cs); #elif ME_UNIX_LIKE && ME_COMPILER_HAS_SPINLOCK rc = pthread_spin_trylock(&lock->cs) != 0; #elif ME_UNIX_LIKE rc = pthread_mutex_trylock(&lock->cs) != 0; #elif ME_WIN_LIKE rc = (lock->freed) ? 0 : (TryEnterCriticalSection(&lock->cs) == 0); #elif VXWORKS rc = semTake(lock->cs, NO_WAIT) != OK; #endif #if ME_DEBUG && COSTLY if (rc == 0) { assert(lock->owner != mprGetCurrentOsThread()); lock->owner = mprGetCurrentOsThread(); } #endif return (rc) ? 0 : 1; }
/* Start the dispatcher by putting it on the runQ. This prevents the event service from starting any events in parallel. The invoking thread should service events directly by calling mprServiceEvents or mprWaitForEvent. */ PUBLIC int mprStartDispatcher(MprDispatcher *dispatcher) { if (dispatcher->owner && dispatcher->owner != mprGetCurrentOsThread()) { mprLog("error mpr event", 0, "Cannot start dispatcher - owned by another thread"); return MPR_ERR_BAD_STATE; } if (!isRunning(dispatcher)) { queueDispatcher(dispatcher->service->runQ, dispatcher); } dispatcher->owner = mprGetCurrentOsThread(); return 0; }
PUBLIC int mprStopDispatcher(MprDispatcher *dispatcher) { if (dispatcher->owner != mprGetCurrentOsThread()) { assert(dispatcher->owner == mprGetCurrentOsThread()); return MPR_ERR_BAD_STATE; } if (!isRunning(dispatcher)) { assert(isRunning(dispatcher)); return MPR_ERR_BAD_STATE; } dispatcher->owner = 0; dequeueDispatcher(dispatcher); mprScheduleDispatcher(dispatcher); return 0; }
static void testCriticalSection(MprTestGroup *gp) { int i, size; mprLock(mutex); size = sizeof(critical) / sizeof(MprThread*); for (i = 0; i < size; i++) { critical[i] = mprGetCurrentOsThread(); } for (i = 0; i < size; i++) { assert(critical[i] == mprGetCurrentOsThread()); } mprUnlock(mutex); }
/* Run events for a dispatcher in a worker thread. When complete, reschedule the dispatcher as required. */ static void dispatchEventsWorker(MprDispatcher *dispatcher) { if (dispatcher->flags & MPR_DISPATCHER_DESTROYED) { /* Dispatcher destroyed after worker started */ return; } dispatcher->owner = mprGetCurrentOsThread(); dispatchEvents(dispatcher); assert(dispatcher->owner == 0 || dispatcher->owner == mprGetCurrentOsThread()); dispatcher->owner = 0; if (!(dispatcher->flags & MPR_DISPATCHER_DESTROYED)) { dequeueDispatcher(dispatcher); mprScheduleDispatcher(dispatcher); } }
PUBLIC void mprLock(MprMutex *lock) { if (lock == NULL) return; #if PLATFORM_LINUX pthread_mutex_lock(&lock->cs); #endif lock->owner = mprGetCurrentOsThread(); }
/* * If this thread is not responsibile for running the Mpr dispatcher then return true. */ bool mprMustWakeDispatcher(MprCtx ctx) { Mpr *mpr; mpr = mprGetMpr(ctx); #if BLD_FEATURE_MULTITHREAD return mprGetCurrentOsThread() != mpr->serviceThread; #else return 0; #endif }
/* Wait for an event to occur on the dispatcher and service the event. This is not called by mprServiceEvents. The dispatcher may be "started" and owned by the thread, or it may be unowned. WARNING: the event may have already happened by the time this API is invoked. WARNING: this will enable GC while sleeping. */ PUBLIC int mprWaitForEvent(MprDispatcher *dispatcher, MprTicks timeout, int64 mark) { MprEventService *es; MprTicks expires, delay; int runEvents, changed; if (dispatcher == NULL) { dispatcher = MPR->dispatcher; } if (dispatcher->flags & MPR_DISPATCHER_DESTROYED) { return 0; } if ((runEvents = (dispatcher->owner == mprGetCurrentOsThread())) != 0) { /* Called from an event on a running dispatcher */ assert(isRunning(dispatcher) || (dispatcher->flags & MPR_DISPATCHER_DESTROYED)); if (dispatchEvents(dispatcher)) { return 0; } } es = MPR->eventService; es->now = mprGetTicks(); expires = timeout < 0 ? MPR_MAX_TIMEOUT : (es->now + timeout); if (expires < 0) { expires = MPR_MAX_TIMEOUT; } delay = expires - es->now; lock(es); delay = getDispatcherIdleTicks(dispatcher, delay); dispatcher->flags |= MPR_DISPATCHER_WAITING; changed = dispatcher->mark != mark && mark != -1; unlock(es); if (changed) { return 0; } mprYield(MPR_YIELD_STICKY); mprWaitForCond(dispatcher->cond, delay); mprResetYield(); es->now = mprGetTicks(); lock(es); dispatcher->flags &= ~MPR_DISPATCHER_WAITING; unlock(es); if (runEvents) { dispatchEvents(dispatcher); assert(isRunning(dispatcher) || (dispatcher->flags & MPR_DISPATCHER_DESTROYED)); } return 0; }
PUBLIC int mprTryLock(MprMutex *lock) { int rc; if (lock == NULL) return 0; #if PLATFORM_LINUX rc = (pthread_mutex_trylock(&lock->cs) != 0); #endif lock->owner = mprGetCurrentOsThread(); return (rc) ? 0 : 1; }
/* Lock a mutex */ PUBLIC void mprLock(MprMutex *lock) { if (lock == 0) return; #if ME_UNIX_LIKE pthread_mutex_lock(&lock->cs); #elif ME_WIN_LIKE if (!lock->freed) { EnterCriticalSection(&lock->cs); } #elif VXWORKS semTake(lock->cs, WAIT_FOREVER); #endif #if ME_DEBUG /* Store last locker only */ lock->owner = mprGetCurrentOsThread(); #endif }
/* Try to attain a lock. Do not block! Returns true if the lock was attained. */ PUBLIC bool mprTryLock(MprMutex *lock) { int rc; if (lock == 0) return 0; #if ME_UNIX_LIKE rc = pthread_mutex_trylock(&lock->cs) != 0; #elif ME_WIN_LIKE rc = TryEnterCriticalSection(&lock->cs) == 0; #elif VXWORKS rc = semTake(lock->cs, NO_WAIT) != OK; #endif #if ME_DEBUG lock->owner = mprGetCurrentOsThread(); #endif return (rc) ? 0 : 1; }
/* Get the next (ready) dispatcher off given runQ and move onto the runQ */ static MprDispatcher *getNextReadyDispatcher(MprEventService *es) { MprDispatcher *dp, *next, *pendingQ, *readyQ, *waitQ, *dispatcher; MprEvent *event; waitQ = es->waitQ; readyQ = es->readyQ; pendingQ = es->pendingQ; dispatcher = 0; lock(es); if (pendingQ->next != pendingQ && mprAvailableWorkers() > 0) { dispatcher = pendingQ->next; } else if (readyQ->next == readyQ) { /* ReadyQ is empty, try to transfer a dispatcher with due events onto the readyQ */ for (dp = waitQ->next; dp != waitQ; dp = next) { next = dp->next; event = dp->eventQ->next; if (event->due <= es->now) { queueDispatcher(es->readyQ, dp); break; } } } if (!dispatcher && readyQ->next != readyQ) { dispatcher = readyQ->next; } /* Reserve the dispatcher. This may get transferred to a worker */ if (dispatcher) { dispatcher->owner = mprGetCurrentOsThread(); } unlock(es); return dispatcher; }
/* Run events for a dispatcher */ static int dispatchEvents(MprDispatcher *dispatcher) { MprEventService *es; MprEvent *event; MprOsThread priorOwner; int count; if (mprIsStopped()) { return 0; } assert(isRunning(dispatcher)); es = dispatcher->service; priorOwner = dispatcher->owner; assert(priorOwner == 0 || priorOwner == mprGetCurrentOsThread()); dispatcher->owner = mprGetCurrentOsThread(); /* Events are removed from the dispatcher queue and put onto the currentQ. This is so they will be marked for GC. If the callback calls mprRemoveEvent, it will not remove from the currentQ. If it was a continuous event, mprRemoveEvent will clear the continuous flag. OPT - this could all be simpler if dispatchEvents was never called recursively. Then a currentQ would not be needed, and neither would a running flag. See mprRemoveEvent(). */ for (count = 0; (event = mprGetNextEvent(dispatcher)) != 0; count++) { assert(!(event->flags & MPR_EVENT_RUNNING)); event->flags |= MPR_EVENT_RUNNING; assert(event->proc); mprAtomicAdd64(&dispatcher->mark, 1); (event->proc)(event->data, event); if (event->cond) { mprSignalCond(event->cond); } if (dispatcher->flags & MPR_DISPATCHER_DESTROYED) { break; } event->flags &= ~MPR_EVENT_RUNNING; lock(es); if (event->flags & MPR_EVENT_CONTINUOUS) { /* Reschedule if continuous */ if (event->next) { mprDequeueEvent(event); } event->timestamp = dispatcher->service->now; event->due = event->timestamp + (event->period ? event->period : 1); mprQueueEvent(dispatcher, event); } else { mprDequeueEvent(event); } es->eventCount++; unlock(es); assert(dispatcher->owner == mprGetCurrentOsThread()); } dispatcher->owner = priorOwner; return count; }
static ulong sslThreadId() { return (long) mprGetCurrentOsThread(); }