int aioPoll(int microSeconds) { int fd; fd_set rd, wr, ex; unsigned long long us; FPRINTF((stderr, "aioPoll(%d)\n", microSeconds)); DO_TICK(SHOULD_TICK()); /* get out early if there is no pending i/o and no need to relinquish cpu */ if ((maxFd == 0) && (microSeconds == 0)) return 0; rd= rdMask; wr= wrMask; ex= exMask; us= ioUTCMicroseconds(); for (;;) { struct timeval tv; int n; unsigned long long now; tv.tv_sec= microSeconds / 1000000; tv.tv_usec= microSeconds % 1000000; n= select(maxFd, &rd, &wr, &ex, &tv); if (n > 0) break; if (n == 0) return 0; if (errno && (EINTR != errno)) { fprintf(stderr, "errno %d\n", errno); perror("select"); return 0; } now= ioUTCMicroseconds(); microSeconds -= max(now - us,1); if (microSeconds <= 0) return 0; us= now; } for (fd= 0; fd < maxFd; ++fd) { # define _DO(FLAG, TYPE) \ { \ if (FD_ISSET(fd, &TYPE)) \ { \ aioHandler handler= TYPE##Handler[fd]; \ FD_CLR(fd, &TYPE##Mask); \ TYPE##Handler[fd]= undefinedHandler; \ handler(fd, clientData[fd], FLAG); \ } \ } _DO_FLAG_TYPE(); # undef _DO } return 1; }
void fakevm() { while (1) { (void)ioUTCMicroseconds(); if ((vmcount += 1ULL) % CHECK_COUNT == 0 && ioHeartbeatFrequency(0) == 0) lockedup("in vm"); if (checkForEvents) { checkForEvents = 0; ioSynchronousCheckForEvents(); } } }
/* Add or remove a synchronous tickee. If periodms is non zero add the tickee * calling it every periodms, aligned to roundms, if non-zero. If periodms is * zero, remove tickee. */ void addSynchronousTickee(void (*tickee)(void), unsigned periodms, unsigned roundms) { int i; if (!periodms) { for (i = 0; i < numSyncTickees; i++) if (synch[i].tickee == tickee) { --numSyncTickees; if (i < numSyncTickees) memmove(synch + i, synch + i + 1, sizeof(synch[i]) * (numSyncTickees - i)); return; } return; } for (i = 0; i < NUM_SYNCHRONOUS_TICKEES; i++) if (i >= numSyncTickees || !synch[i].tickee || synch[i].tickee == tickee) { synch[i].tickee = tickee; synch[i].tickeePeriodUsecs = periodms * MicrosecondsPerMillisecond; synch[i].tickeeDeadlineUsecs = synch[i].tickeePeriodUsecs + ioUTCMicroseconds(); if (roundms) { synch[i].tickeeDeadlineUsecs -= synch[i].tickeeDeadlineUsecs % (roundms * MicrosecondsPerMillisecond); if (synch[i].tickeeDeadlineUsecs < ioUTCMicroseconds()) synch[i].tickeeDeadlineUsecs += synch[i].tickeePeriodUsecs; } if (i >= numSyncTickees) ++numSyncTickees; return; } error("ran out of synchronous tickee slots"); }
void hptick(void) { unsigned long long start = ioUTCMicroseconds(); yield = 1; sqLowLevelMFence(); while (ioUTCMicroseconds() - start < hptickusecs) if ((hpcount += 1ULL) % CHECK_COUNT == 0 && ioHeartbeatFrequency(0) == 0) lockedup("in hptick"); yield = 0; sqLowLevelMFence(); if (yieldMethod == yield_via_wait_signal) { if (pthread_mutex_trylock(&yield_sync) == 0) {/* success */ pthread_mutex_unlock(&yield_sync); not_blocked_count += 1; } else { pthread_cond_signal(&yield_cond); unblock_count += 1; } } }
void ioSynchronousCheckForEvents() { int i; #if ITIMER_HEARTBEAT extern void yieldToHighPriorityTickerThread(void); sqLowLevelMFence(); if (shouldYieldToHighPriorityTickerThread) yieldToHighPriorityTickerThread(); #endif for (i = 0; i < numSyncTickees; i++) if (synch[i].tickee && ioUTCMicroseconds() >= synch[i].tickeeDeadlineUsecs) { synch[i].tickeeDeadlineUsecs += synch[i].tickeePeriodUsecs; synch[i].tickee(); } }
/* Add or remove an asynchronous tickee. If periodms is non zero add the * tickee, calling it every periodms. * * N.B. addHighPriorityTickee is called from the VM thread, whereas * checkHighPriorityTickees is called from the high-priority heartbeat thread * (or an interrupt). The above 64-bit variables must therefore be read and * written atomically to avoid either thread reading or writing a modified * half of the variable while the other half has yet to be updated. */ void addHighPriorityTickee(void (*tickee)(void), unsigned periodms) { int i; if (!periodms) { for (i = 0; i < numAsyncTickees; i++) /* We cannot safely copy the data to keep used tickees contiguous * because checkHighPriorityTickees could be called during the move. * This implies first checking for an existing tickee below before * using an empty slot because an empty slot can be created before * a used (and subsequently modified) tickee. */ if (async[i].tickee == tickee) { async[i].tickee = 0; sqLowLevelMFence(); return; } return; } for (i = 0; i < numAsyncTickees; i++) if (async[i].tickee == tickee) break; if (i >= numAsyncTickees) for (i = 0; i < NUM_ASYNCHRONOUS_TICKEES; i++) if (i >= numAsyncTickees || !async[i].tickee) break; if (i >= NUM_ASYNCHRONOUS_TICKEES) error("ran out of asyncronous tickee slots"); /* first disable the tickee while updating the entry. */ async[i].tickee = 0; sqLowLevelMFence(); async[i].tickeePeriodUsecs = periodms * MicrosecondsPerMillisecond; async[i].tickeeDeadlineUsecs = async[i].tickeePeriodUsecs + ioUTCMicroseconds(); async[i].inProgress = 0; async[i].tickee = tickee; if (i >= numAsyncTickees) ++numAsyncTickees; sqLowLevelMFence(); }