#include <assert.h>
#include "osi.h"
+#include "osi_internal.h"
+
/* Locking hierarchy for these critical sections:
*
* 1. lock osi_sleepFDCS
* Releases the reference count and frees the structure if the item has
* been deleted.
*/
-void osi_ReleaseSleepInfo(osi_sleepInfo_t *ap)
+void osi_ReleaseSleepInfo(osi_sleepInfo_t *sp)
{
- if (--ap->refCount == 0 && (ap->states & OSI_SLEEPINFO_DELETED))
- osi_FreeSleepInfo(ap);
+ if (InterlockedDecrement(&sp->refCount) == 0 && (sp->states & OSI_SLEEPINFO_DELETED))
+ osi_FreeSleepInfo(sp);
}
/* must be called with sleep bucket locked.
* from the hash bucket). Otherwise, we simply mark the item
* for deleting when the ref count hits zero.
*/
-void osi_FreeSleepInfo(osi_sleepInfo_t *ap)
+void osi_FreeSleepInfo(osi_sleepInfo_t *sp)
{
LONG_PTR idx;
- if (ap->refCount > 0) {
+ if (sp->refCount > 0) {
TlsSetValue(osi_SleepSlot, NULL); /* don't reuse me */
- ap->states |= OSI_SLEEPINFO_DELETED;
+ _InterlockedOr(&sp->states, OSI_SLEEPINFO_DELETED);
return;
}
/* remove from hash if still there */
- if (ap->states & OSI_SLEEPINFO_INHASH) {
- ap->states &= ~OSI_SLEEPINFO_INHASH;
- idx = osi_SLEEPHASH(ap->value);
- osi_QRemoveHT((osi_queue_t **) &osi_sleepers[idx], (osi_queue_t **) &osi_sleepersEnd[idx], &ap->q);
+ if (sp->states & OSI_SLEEPINFO_INHASH) {
+ idx = osi_SLEEPHASH(sp->value);
+ osi_QRemoveHT((osi_queue_t **) &osi_sleepers[idx], (osi_queue_t **) &osi_sleepersEnd[idx], &sp->q);
+ _InterlockedAnd(&sp->states, ~OSI_SLEEPINFO_INHASH);
}
- if (ap->states & OSI_SLEEPINFO_DELETED) {
+ if (sp->states & OSI_SLEEPINFO_DELETED) {
EnterCriticalSection(&osi_sleepInfoAllocCS);
- ap->q.nextp = (osi_queue_t *) osi_sleepInfoFreeListp;
- osi_sleepInfoFreeListp = ap;
- osi_sleepInfoCount++;
+ sp->q.nextp = (osi_queue_t *) osi_sleepInfoFreeListp;
+ osi_sleepInfoFreeListp = sp;
+ _InterlockedAnd(&sp->states, ~OSI_SLEEPINFO_DELETED);
+ InterlockedIncrement(&osi_sleepInfoCount);
LeaveCriticalSection(&osi_sleepInfoAllocCS);
}
}
/* allocate a new sleep structure from the free list */
osi_sleepInfo_t *osi_AllocSleepInfo()
{
- osi_sleepInfo_t *ap;
+ osi_sleepInfo_t *sp;
EnterCriticalSection(&osi_sleepInfoAllocCS);
- if (!(ap = osi_sleepInfoFreeListp)) {
- ap = (osi_sleepInfo_t *) malloc(sizeof(osi_sleepInfo_t));
- ap->sema = CreateSemaphore(NULL, 0, 65536, (char *) 0);
- osi_sleepInfoAllocs++;
+ if (!(sp = osi_sleepInfoFreeListp)) {
+ sp = (osi_sleepInfo_t *) malloc(sizeof(osi_sleepInfo_t));
+ memset(sp, 0, sizeof(*sp));
+ sp->sema = CreateSemaphore(NULL, 0, 65536, NULL);
+ InterlockedIncrement(&osi_sleepInfoAllocs);
}
else {
- osi_sleepInfoFreeListp = (osi_sleepInfo_t *) ap->q.nextp;
- osi_sleepInfoCount--;
+ osi_sleepInfoFreeListp = (osi_sleepInfo_t *) sp->q.nextp;
+ InterlockedDecrement(&osi_sleepInfoCount);
}
- ap->tid = GetCurrentThreadId();
- ap->states = 0; /* not signalled yet */
+ sp->tid = GetCurrentThreadId();
LeaveCriticalSection(&osi_sleepInfoAllocCS);
- return ap;
+ return sp;
}
int osi_Once(osi_once_t *argp)
TlsSetValue(osi_SleepSlot, sp);
}
else {
- sp->states = 0;
+ _InterlockedAnd(&sp->states, 0);
}
- sp->refCount = 0;
sp->waitFor = waitFor;
sp->value = (LONG_PTR) patchp;
- sp->tidp = tidp;
+ sp->tidp = tidp;
+ sp->idx = -1;
if (prepend)
osi_QAddH((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &sp->q);
else
sp = turnp->lastp;
osi_QRemoveHT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &sp->q);
- sp->states |= OSI_SLEEPINFO_SIGNALLED;
- ReleaseSemaphore(sp->sema, 1, (long *) 0);
+ _InterlockedOr(&sp->states, OSI_SLEEPINFO_SIGNALLED);
+ ReleaseSemaphore(sp->sema, 1, NULL);
}
/* like TSignal, only wake *everyone* */
while(sp = turnp->lastp) {
osi_QRemoveHT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &sp->q);
- sp->states |= OSI_SLEEPINFO_SIGNALLED;
- ReleaseSemaphore(sp->sema, 1, (long *) 0);
+ _InterlockedOr(&sp->states, OSI_SLEEPINFO_SIGNALLED);
+ ReleaseSemaphore(sp->sema, 1, NULL);
} /* while someone's still asleep */
}
* after the ReleaseSemaphore, if a context swap occurs.
*/
nsp = (osi_sleepInfo_t *) tsp->q.nextp;
- tsp->states |= OSI_SLEEPINFO_SIGNALLED;
- ReleaseSemaphore(tsp->sema, 1, (long *) 0);
+ _InterlockedOr(&tsp->states, OSI_SLEEPINFO_SIGNALLED);
+ ReleaseSemaphore(tsp->sema, 1, NULL);
}
}
*/
void osi_SleepSpin(LONG_PTR sleepValue, CRITICAL_SECTION *releasep)
{
- LONG_PTR idx;
int code;
osi_sleepInfo_t *sp;
CRITICAL_SECTION *csp;
TlsSetValue(osi_SleepSlot, sp);
}
else {
- sp->states = 0;
+ _InterlockedAnd(&sp->states, 0);
}
- sp->refCount = 0;
+ sp->waitFor = 0;
sp->value = sleepValue;
- idx = osi_SLEEPHASH(sleepValue);
- csp = &osi_critSec[idx];
+ sp->tidp = NULL;
+ sp->idx = osi_SLEEPHASH(sleepValue);
+ csp = &osi_critSec[sp->idx];
EnterCriticalSection(csp);
- osi_QAddT((osi_queue_t **) &osi_sleepers[idx], (osi_queue_t **) &osi_sleepersEnd[idx], &sp->q);
- sp->states |= OSI_SLEEPINFO_INHASH;
- LeaveCriticalSection(releasep);
+ osi_QAddT((osi_queue_t **) &osi_sleepers[sp->idx], (osi_queue_t **) &osi_sleepersEnd[sp->idx], &sp->q);
+ _InterlockedOr(&sp->states, OSI_SLEEPINFO_INHASH);
LeaveCriticalSection(csp);
- osi_totalSleeps++; /* stats */
+ LeaveCriticalSection(releasep);
+ InterlockedIncrement(&osi_totalSleeps); /* stats */
while(1) {
/* wait */
code = WaitForSingleObject(sp->sema,
idx = osi_SLEEPHASH(sleepValue);
csp = &osi_critSec[idx];
EnterCriticalSection(csp);
- for(tsp=osi_sleepers[idx]; tsp; tsp=(osi_sleepInfo_t *) osi_QNext(&tsp->q)) {
- if ((!(tsp->states & (OSI_SLEEPINFO_DELETED|OSI_SLEEPINFO_SIGNALLED)))
- && tsp->value == sleepValue) {
- ReleaseSemaphore(tsp->sema, 1, (long *) 0);
- tsp->states |= OSI_SLEEPINFO_SIGNALLED;
- }
- }
+ for(tsp=osi_sleepers[idx]; tsp; tsp=(osi_sleepInfo_t *) osi_QNext(&tsp->q)) {
+ if ((!(tsp->states & (OSI_SLEEPINFO_DELETED|OSI_SLEEPINFO_SIGNALLED)))
+ && tsp->value == sleepValue) {
+ _InterlockedOr(&tsp->states, OSI_SLEEPINFO_SIGNALLED);
+ ReleaseSemaphore(tsp->sema, 1, NULL);
+ }
+ }
LeaveCriticalSection(csp);
}
if ((sip = cp->sip) == NULL) {
sip = osi_sleepers[idx];
if (!sip) idx++;
- else sip->refCount++;
+ else
+ InterlockedIncrement(&sip->refCount);
}
else {
/* it is safe to release the current sleep info guy now
sip = nsip;
if (sip)
- sip->refCount++;
+ InterlockedIncrement(&sip->refCount);
else
idx++;
}