PUBLIC void mprDestroyDispatcher(MprDispatcher *dispatcher) { MprEventService *es; MprEvent *q, *event, *next; if (dispatcher) { es = dispatcher->service; assert(es == MPR->eventService); lock(es); assert(dispatcher->service == MPR->eventService); q = dispatcher->eventQ; if (q) { for (event = q->next; event != q; event = next) { next = event->next; if (event->cond) { mprSignalCond(event->cond); } if (event->dispatcher) { mprRemoveEvent(event); } } } dequeueDispatcher(dispatcher); dispatcher->flags |= MPR_DISPATCHER_DESTROYED; unlock(es); } }
PUBLIC int mprNotifyOn(MprWaitService *ws, MprWaitHandler *wp, int mask) { int winMask; assert(ws->hwnd); lock(ws); winMask = 0; if (wp->desiredMask != mask) { if (mask & MPR_READABLE) { winMask |= FD_ACCEPT | FD_CONNECT | FD_CLOSE | FD_READ; } if (mask & MPR_WRITABLE) { winMask |= FD_WRITE; } wp->desiredMask = mask; WSAAsyncSelect(wp->fd, ws->hwnd, ws->socketMessage, winMask); if (wp->event) { mprRemoveEvent(wp->event); wp->event = 0; } } unlock(ws); return 0; }
/* Timer callback */ static void timerCallback(void *data, MprEvent *event) { mprLock(app->mutex); if (--app->markCount == 0) { mprSignalCond(app->complete); } mprRemoveEvent(event); mprUnlock(app->mutex); }
/* Event callback */ static void eventCallback(void *data, MprEvent *event) { // TODO - should have atomic Inc mprLock(app->mutex); if (--app->markCount == 0) { mprSignalCond(app->complete); } mprRemoveEvent(event); mprUnlock(app->mutex); }
/* Destroy the http service. This should be called only after ensuring all running requests have completed. Normally invoked by the http terminator from mprDestroy */ PUBLIC void httpDestroy() { Http *http; if ((http = HTTP) == 0) { return; } httpStopConnections(0); httpStopEndpoints(); httpSetDefaultHost(0); if (http->timer) { mprRemoveEvent(http->timer); http->timer = 0; } if (http->timestamp) { mprRemoveEvent(http->timestamp); http->timestamp = 0; } MPR->httpService = NULL; }
void *mprDestroyCache(MprCache *cache) { mprAssert(cache); if (cache->timer && cache != shared) { mprRemoveEvent(cache->timer); cache->timer = 0; } if (cache == shared) { shared = 0; } return 0; }
static void commonPrep(HttpConn *conn) { if (conn->timeoutEvent) { mprRemoveEvent(conn->timeoutEvent); conn->timeoutEvent = 0; } conn->lastActivity = conn->http->now; conn->error = 0; conn->errorMsg = 0; conn->state = 0; conn->authRequested = 0; httpSetState(conn, HTTP_STATE_BEGIN); httpInitSchedulerQueue(conn->serviceq); }
PUBLIC void httpSetTimestamp(MprTicks period) { Http *http; http = HTTP; if (period < (10 * TPS)) { period = (10 * TPS); } if (http->timestamp) { mprRemoveEvent(http->timestamp); } if (period > 0) { http->timestamp = mprCreateTimerEvent(NULL, "httpTimestamp", period, timestamp, NULL, MPR_EVENT_CONTINUOUS | MPR_EVENT_QUICK); } }
PUBLIC void mprDestroyWaitHandler(MprWaitHandler *wp) { MprWaitService *ws; if (wp == 0) { return; } ws = wp->service; lock(ws); if (wp->fd >= 0) { mprRemoveWaitHandler(wp); wp->fd = INVALID_SOCKET; if (wp->event) { mprRemoveEvent(wp->event); wp->event = 0; } } wp->dispatcher = 0; unlock(ws); }
PUBLIC void mprRescheduleEvent(MprEvent *event, MprTicks period) { MprEventService *es; MprDispatcher *dispatcher; int continuous; dispatcher = event->dispatcher; es = dispatcher->service; lock(es); event->period = period; event->timestamp = es->now; event->due = event->timestamp + period; if (event->next) { continuous = event->flags & MPR_EVENT_CONTINUOUS; mprRemoveEvent(event); event->flags |= continuous; } unlock(es); mprQueueEvent(dispatcher, event); }
/* The http timer does maintenance activities and will fire per second while there are active requests. This routine will also be called by httpTerminate with event == 0 to signify a shutdown. NOTE: Because we lock the http here, connections cannot be deleted while we are modifying the list. */ static void httpTimer(Http *http, MprEvent *event) { HttpConn *conn; HttpStage *stage; HttpLimits *limits; MprModule *module; int next, active, abort; updateCurrentDate(); /* Check for any inactive connections or expired requests (inactivityTimeout and requestTimeout) OPT - could check for expired connections every 10 seconds. */ lock(http->connections); for (active = 0, next = 0; (conn = mprGetNextItem(http->connections, &next)) != 0; active++) { limits = conn->limits; if (!conn->timeoutEvent) { abort = mprIsStopping(); if (httpServerConn(conn) && (HTTP_STATE_CONNECTED < conn->state && conn->state < HTTP_STATE_PARSED) && (http->now - conn->started) > limits->requestParseTimeout) { conn->timeout = HTTP_PARSE_TIMEOUT; abort = 1; } else if ((http->now - conn->lastActivity) > limits->inactivityTimeout) { conn->timeout = HTTP_INACTIVITY_TIMEOUT; abort = 1; } else if ((http->now - conn->started) > limits->requestTimeout) { conn->timeout = HTTP_REQUEST_TIMEOUT; abort = 1; } else if (!event) { /* Called directly from httpStop to stop connections */ if (MPR->exitTimeout > 0) { if (conn->state == HTTP_STATE_COMPLETE || (HTTP_STATE_CONNECTED < conn->state && conn->state < HTTP_STATE_PARSED)) { abort = 1; } } else { abort = 1; } } if (abort && !mprGetDebugMode()) { httpScheduleConnTimeout(conn); } } } /* Check for unloadable modules OPT - could check for modules every minute */ if (mprGetListLength(http->connections) == 0) { for (next = 0; (module = mprGetNextItem(MPR->moduleService->modules, &next)) != 0; ) { if (module->timeout) { if (module->lastActivity + module->timeout < http->now) { mprLog("info http", 2, "Unloading inactive module %s", module->name); if ((stage = httpLookupStage(module->name)) != 0) { if (mprUnloadModule(module) < 0) { active++; } else { stage->flags |= HTTP_STAGE_UNLOADED; } } else { mprUnloadModule(module); } } else { active++; } } } } httpPruneMonitors(); if (active == 0 || mprIsStopping()) { if (event) { mprRemoveEvent(event); } http->timer = 0; /* Going to sleep now, so schedule a GC to free as much as possible. */ mprGC(MPR_GC_FORCE | MPR_GC_NO_BLOCK); } else { mprGC(MPR_GC_NO_BLOCK); } unlock(http->connections); }
static void pruneCache(MprCache *cache, MprEvent *event) { MprTime when, factor; MprKey *kp; CacheItem *item; ssize excessKeys; if (!cache) { cache = shared; if (!cache) { return; } } if (event) { when = mprGetTime(); } else { /* Expire all items by setting event to NULL */ when = MAXINT64; } if (mprTryLock(cache->mutex)) { /* Check for expired items */ for (kp = 0; (kp = mprGetNextKey(cache->store, kp)) != 0; ) { item = (CacheItem*) kp->data; mprLog(6, "Cache: \"%s\" lifespan %d, expires in %d secs", item->key, item->lifespan / 1000, (item->expires - when) / 1000); if (item->expires && item->expires <= when) { mprLog(5, "Cache prune expired key %s", kp->key); removeItem(cache, item); } } mprAssert(cache->usedMem >= 0); /* If too many keys or too much memory used, prune keys that expire soonest. */ if (cache->maxKeys < MAXSSIZE || cache->maxMem < MAXSSIZE) { /* Look for those expiring in the next 5 minutes, then 20 mins, then 80 ... */ excessKeys = mprGetHashLength(cache->store) - cache->maxKeys; factor = 5 * 60 * MPR_TICKS_PER_SEC; when += factor; while (excessKeys > 0 || cache->usedMem > cache->maxMem) { for (kp = 0; (kp = mprGetNextKey(cache->store, kp)) != 0; ) { item = (CacheItem*) kp->data; if (item->expires && item->expires <= when) { mprLog(5, "Cache too big execess keys %Ld, mem %Ld, prune key %s", excessKeys, (cache->maxMem - cache->usedMem), kp->key); removeItem(cache, item); } } factor *= 4; when += factor; } } mprAssert(cache->usedMem >= 0); if (mprGetHashLength(cache->store) == 0) { if (event) { mprRemoveEvent(event); cache->timer = 0; } } unlock(cache); } }