diff options
author | seawood%netscape.com <devnull@localhost> | 2002-02-16 02:25:51 +0000 |
---|---|---|
committer | seawood%netscape.com <devnull@localhost> | 2002-02-16 02:25:51 +0000 |
commit | b93c63183e29aa6c14e2d95015eda2aec9f0671b (patch) | |
tree | 6ff135c4fb6cb82fd50b96011bb60cb7e3be6634 | |
parent | 5cc970ff507fb34535ca3b7f706f45434de462fd (diff) | |
download | nspr-hg-b93c63183e29aa6c14e2d95015eda2aec9f0671b.tar.gz |
Add "fast RAM semaphore" support.
Thanks to Mike Kaply <mkaply@us.ibm.com> for the patch.
Bug #125123 r=wtc
-rw-r--r-- | pr/include/md/_os2.h | 33 | ||||
-rw-r--r-- | pr/src/md/os2/os2cv.c | 95 | ||||
-rw-r--r-- | pr/src/md/os2/os2vacpp.asm | 259 |
3 files changed, 375 insertions, 12 deletions
diff --git a/pr/include/md/_os2.h b/pr/include/md/_os2.h index 9f2e6dcf..799901e2 100644 --- a/pr/include/md/_os2.h +++ b/pr/include/md/_os2.h @@ -47,6 +47,33 @@ #include <errno.h> +#define USE_RAMSEM + +#ifdef USE_RAMSEM +#pragma pack(4) + +#pragma pack(2) +typedef struct _RAMSEM +{ + ULONG ulTIDPID; + ULONG hevSem; + ULONG cLocks; + USHORT cWaiting; + USHORT cPosts; +} RAMSEM, *PRAMSEM; + +typedef struct _CRITICAL_SECTION +{ + ULONG ulReserved[4]; /* Same size as RAMSEM */ +} CRITICAL_SECTION, *PCRITICAL_SECTION, *LPCRITICAL_SECTION; +#pragma pack(4) + +VOID APIENTRY DeleteCriticalSection(PCRITICAL_SECTION); +VOID APIENTRY EnterCriticalSection(PCRITICAL_SECTION); +VOID APIENTRY InitializeCriticalSection(PCRITICAL_SECTION); +VOID APIENTRY LeaveCriticalSection(PCRITICAL_SECTION); +#endif + #ifdef XP_OS2_EMX /* * EMX-specific tweaks: @@ -162,7 +189,11 @@ struct _MDNotified { }; struct _MDLock { - HMTX mutex; /* this is recursive on NT */ +#ifdef USE_RAMSEM + CRITICAL_SECTION mutex; /* this is recursive on NT */ +#else + HMTX mutex; /* this is recursive on NT */ +#endif /* * When notifying cvars, there is no point in actually diff --git a/pr/src/md/os2/os2cv.c b/pr/src/md/os2/os2cv.c index 1a2d9399..ccd1e92f 100644 --- a/pr/src/md/os2/os2cv.c +++ b/pr/src/md/os2/os2cv.c @@ -48,6 +48,40 @@ #include "primpl.h" +#ifdef USE_RAMSEM +ULONG _Far16 _Pascal Dos16GetInfoSeg(PSEL pselGlobal, PSEL pselLocal); +APIRET _Optlink SemRequest486(PRAMSEM, ULONG); +APIRET _Optlink SemReleasex86(PRAMSEM, ULONG); + +typedef struct _LINFOSEG +{ + USHORT pidCurrent; + USHORT pidParent; + USHORT prtyCurrent; + USHORT tidCurrent; + USHORT sgCurrent; + UCHAR rfProcStatus; + UCHAR dummy1; + BOOL16 fForeground; + UCHAR typProcess; + UCHAR dummy2; + SEL selEnvironment; + USHORT offCmdLine; + USHORT cbDataSegment; + USHORT cbStack; + USHORT cbHeap; + USHORT hmod; + SEL selDS; + SEL selPack; + SEL selPackShr; + SEL selPackPck; + ULONG ulReserved; +} LINFOSEG; +typedef LINFOSEG FAR *PLINFOSEG; + +PLINFOSEG plisCurrent = NULL; +#endif + /* * AddThreadToCVWaitQueueInternal -- * @@ -163,7 +197,11 @@ md_UnlockAndPostNotifies( } /* Release the lock before notifying */ - DosReleaseMutexSem(lock->mutex); +#ifdef USE_RAMSEM + SemReleasex86(&lock->mutex, 0); +#else + DosReleaseMutexSem(lock->mutex); +#endif notified = &post; /* this is where we start */ do { @@ -270,7 +308,11 @@ _PR_MD_WAIT_CV(_MDCVar *cv, _MDLock *lock, PRIntervalTime timeout ) md_UnlockAndPostNotifies(lock, thred, cv); } else { AddThreadToCVWaitQueueInternal(thred, cv); +#ifdef USE_RAMSEM + SemReleasex86( &lock->mutex, 0 ); +#else DosReleaseMutexSem(lock->mutex); +#endif } /* Wait for notification or timeout; don't really care which */ @@ -279,7 +321,11 @@ _PR_MD_WAIT_CV(_MDCVar *cv, _MDLock *lock, PRIntervalTime timeout ) DosResetEventSem(thred->md.blocked_sema, &count); } +#ifdef USE_RAMSEM + SemRequest486(&(lock->mutex), -1); +#else DosRequestMutexSem((lock->mutex), SEM_INDEFINITE_WAIT); +#endif PR_ASSERT(rv == NO_ERROR || rv == ERROR_TIMEOUT); @@ -336,27 +382,70 @@ _PR_MD_NOTIFY_CV(_MDCVar *cv, _MDLock *lock) PRStatus _PR_MD_NEW_LOCK(_MDLock *lock) { +#ifdef USE_RAMSEM + // It's better if this API traps when pCriticalSect is not a valid + // pointer, because we can't return an error code and if we just return + // the API caller will have nasty bugs that are hard to find. + + PRAMSEM pramsem = (PRAMSEM)(&(lock->mutex)); + /* First time, set up addresses of processor specific functions + */ + if (plisCurrent == NULL) + { + SEL selGlobal = 0, selLocal = 0; + + /* Convert 16 bit global information segment to 32 bit address + * by performing CRMA on the 16 bit address: "shift" operation + * to convert sel to flat, "and" operation to mask the address + * to 32-bit + */ + Dos16GetInfoSeg(&selGlobal, &selLocal); + plisCurrent = (PLINFOSEG)(((ULONG)selLocal << 13) & + (ULONG)0x1fff0000); + + } + + memset(pramsem, 0, sizeof(pramsem)); + DosCreateEventSem(0, &pramsem->hevSem, DC_SEM_SHARED, 0); + + lock->notified.length=0; + lock->notified.link=NULL; + return PR_SUCCESS; +#else DosCreateMutexSem(0, &(lock->mutex), 0, 0); (lock)->notified.length=0; (lock)->notified.link=NULL; return PR_SUCCESS; +#endif } void _PR_MD_FREE_LOCK(_MDLock *lock) { +#ifdef USE_RAMSEM + DosCloseEventSem(((PRAMSEM)(&(lock->mutex)))->hevSem); +#else DosCloseMutexSem(lock->mutex); +#endif } void _PR_MD_LOCK(_MDLock *lock) { +#ifdef USE_RAMSEM + SemRequest486(&(lock->mutex), -1); +#else DosRequestMutexSem(lock->mutex, SEM_INDEFINITE_WAIT); +#endif } PRIntn _PR_MD_TEST_AND_LOCK(_MDLock *lock) { +#ifdef USE_RAMSEM + SemRequest486(&(lock->mutex), -1); +#else DosRequestMutexSem(lock->mutex, SEM_INDEFINITE_WAIT); +#endif return 0; } @@ -373,7 +462,11 @@ _PR_MD_UNLOCK(_MDLock *lock) if (0 != lock->notified.length) { md_UnlockAndPostNotifies(lock, NULL, NULL); } else { +#ifdef USE_RAMSEM + SemReleasex86( &lock->mutex, 0 ); +#else DosReleaseMutexSem(lock->mutex); +#endif } return; } diff --git a/pr/src/md/os2/os2vacpp.asm b/pr/src/md/os2/os2vacpp.asm index 2581323b..eae947f2 100644 --- a/pr/src/md/os2/os2vacpp.asm +++ b/pr/src/md/os2/os2vacpp.asm @@ -30,20 +30,258 @@ COMMENT | -*- Mode: asm; tab-width: 8; c-basic-offset: 4 -*- GPL. Windows uses inline assembly for their atomic functions, so we have - created an assembly file for VACPP on OS/2 + created an assembly file for VACPP on OS/2. + + This assembly file also contains an implementation of RAM semaphores. + + Notes: + The ulTIDPID element of the RAMSEM structure is overloaded in the 386 + implementation to hold the TID:PID in the lower 31 bits and the lock + bit in the high bit | + page ,132 .486P - .MODEL FLAT, OPTLINK - .STACK + ASSUME CS:FLAT, DS:FLAT, SS:FLAT, ES:FLAT, FS:FLAT + + EXTRN Dos32PostEventSem:PROC + EXTRN Dos32WaitEventSem:PROC + EXTRN Dos32ResetEventSem:PROC + +ramsem STRUC + ramsem_ulTIDPID DD ? + ramsem_hevSem DD ? + ramsem_cLocks DD ? + ramsem_cWaiting DW ? + ramsem_cPosts DW ? +ramsem ENDS + +ERROR_SEM_TIMEOUT equ 121 +ERROR_NOT_OWNER equ 288 +SEM_RELEASE_UNOWNED equ 1 +SEM_RELEASE_ALL equ 2 +TS_LOCKBIT equ 31 + + +DATA SEGMENT DWORD USE32 PUBLIC 'DATA' + + EXTRN plisCurrent:DWORD + +DATA ENDS + +CODE32 SEGMENT DWORD USE32 PUBLIC 'CODE' + + PUBLIC SemRequest386 + PUBLIC SemRequest486 + PUBLIC SemReleasex86 + + PUBLIC _PR_MD_ATOMIC_SET + PUBLIC _PR_MD_ATOMIC_ADD + PUBLIC _PR_MD_ATOMIC_INCREMENT + PUBLIC _PR_MD_ATOMIC_DECREMENT + +;;; RAM Semaphores + +;;;--------------------------------------------------------------------------- +;;; APIRET _Optlink SemRequest(PRAMSEM pramsem, ULONG ulTimeout); +;;; +;;; Registers: +;;; EAX - packed TID:PID word +;;; ECX - address of RAMSEM structure +;;; EDX - length of timeout in milli-seconds +;;;--------------------------------------------------------------------------- + + ALIGN 04H +SemRequest386 PROC + mov ecx, eax ; For consistency use ecx + ; for PRAMSEM (see 486 imp) + + push ebx ; Save ebx (volatile) + mov ebx, dword ptr [plisCurrent] + mov eax, dword ptr [ebx+4] ; Place thread id in high + ; word, process id in low + mov ax, word ptr [ebx] ; word + pop ebx ; Restore ebx + +req386_test: + push eax + sub eax, (ramsem PTR [ecx]).ramsem_ulTIDPID ; This thread the owner? + shl eax,1 ; Don't compare top bit + pop eax + jz req386_inc_exit ; increment the use count + + lock inc (ramsem PTR [ecx]).ramsem_cWaiting ; inc waiting flag + +; lock ; Uncomment for SMP + lock bts (ramsem PTR [ecx]).ramsem_ulTIDPID, 31 ; Use the high bit as the + jc req386_sleep ; semaphore + or (ramsem PTR [ecx]).ramsem_ulTIDPID, eax ; Copy the rest of the bits + +req386_inc_exit: + lock inc (ramsem PTR [ecx]).ramsem_cLocks + xor eax,eax + +req386_exit: + ret + +req386_sleep: + push eax ; Save eax (volatile) + push ecx ; Save ecx (volatile) + push edx ; Save edx (volatile) + push edx ; timeout + push (ramsem PTR [ecx]).ramsem_hevSem + call Dos32WaitEventSem + add esp, 8 + pop edx ; restore edx + pop ecx ; restore ecx + or eax, eax + je req386_reset ; If no error, reset + pop edx ; junk stored eax + jmp req386_exit ; Exit, timed out + +req386_reset: + push ecx ; Save ecx (volatile) + push edx ; Save edx (volatile) + sub esp, 4 ; Use stack space for + push esp ; dummy pulPostCt + push (ramsem PTR [ecx]).ramsem_hevSem + call Dos32ResetEventSem + add esp, 12 + pop edx ; restore edx + pop ecx ; restore ecx + pop eax ; restore eax + jmp req386_test ; Retry the semaphore +SemRequest386 ENDP + + ALIGN 04H +SemRequest486 PROC + push ebx ; Save ebx (volatile) + mov ecx, eax ; PRAMSEM must be in ecx, + ; not eax, for cmpxchg + + mov ebx, dword ptr [plisCurrent] + mov eax, dword ptr [ebx+4] ; Place thread id in high + ; word, process id in low + mov ax, word ptr [ebx] ; word + mov ebx,eax + +req486_test: + xor eax,eax + cmp (ramsem PTR [ecx]).ramsem_ulTIDPID, ebx ; If we own the sem, just + jz req486_inc_exit ; increment the use count + + lock inc (ramsem PTR [ecx]).ramsem_cWaiting ; inc waiting flag + +; lock ; Uncomment for SMP + DB 0F0h +; cmpxchg (ramsem PTR [ecx]).ramsem_ulTIDPID, ebx +; (byte 3 is the offset of ulProcessThread into the RAMSEM structure) + DB 00Fh + DB 0B1h + DB 019h + jnz req486_sleep + +req486_inc_exit: + lock inc (ramsem PTR [ecx]).ramsem_cLocks + +req486_exit: + pop ebx ; Restore ebx + ret + +req486_sleep: + push ecx ; Save ecx (volatile) + push edx ; Save edx (volatile) + push edx ; timeout + push (ramsem PTR [ecx]).ramsem_hevSem + call Dos32WaitEventSem + add esp, 8 + pop edx ; restore edx + pop ecx ; restore ecx + or eax, eax + jne req486_exit ; Exit, if error + + push ecx ; Save ecx (volatile) + push edx ; Save edx (volatile) + sub esp, 4 ; Use stack space for + push esp ; dummy pulPostCt + push (ramsem PTR [ecx]).ramsem_hevSem + call Dos32ResetEventSem + add esp, 12 + pop edx ; restore edx + pop ecx ; restore ecx + jmp req486_test ; Retry the semaphore + +SemRequest486 ENDP + +;;;--------------------------------------------------------------------- +;;; APIRET _Optlink SemReleasex86(PRAMSEM pramsem, ULONG flFlags); +;;; +;;; Registers: +;;; EAX - address of RAMSEM structure +;;; ECX - temporary variable +;;; EDX - flags +;;;--------------------------------------------------------------------- + + ALIGN 04H +SemReleasex86 PROC + test edx, SEM_RELEASE_UNOWNED ; If set, don't bother + jnz rel_ownerok ; getting/checking PID/TID + + push ebx ; Save ebx (volatile) + mov ebx, dword ptr [plisCurrent] + mov ecx, dword ptr [ebx+4] ; Place thread id in high + ; word, process id in low + mov cx, word ptr [ebx] ; word + pop ebx ; Restore ebx + + sub ecx, (ramsem PTR [eax]).ramsem_ulTIDPID ; This thread the owner? + shl ecx,1 ; Don't compare top bit + jnz rel_notowner + +rel_ownerok: + test edx, SEM_RELEASE_ALL + jnz rel_clear + + lock dec (ramsem PTR [eax]).ramsem_cLocks + jnz rel_exit + +rel_disown: + mov (ramsem PTR [eax]).ramsem_ulTIDPID, 0 + + lock inc (ramsem PTR [eax]).ramsem_cPosts + mov cx, (ramsem PTR [eax]).ramsem_cWaiting + cmp (ramsem PTR [eax]).ramsem_cPosts, cx + jne rel_post + +rel_exit: + xor eax, eax + ret + +rel_clear: + lock mov (ramsem PTR [eax]).ramsem_cLocks,0 + jmp rel_disown + +rel_notowner: + mov eax, ERROR_NOT_OWNER + ret + +rel_post: + mov (ramsem PTR [eax]).ramsem_cPosts, cx + push (ramsem PTR [eax]).ramsem_hevSem + call Dos32PostEventSem + add esp,4 + xor eax,eax + ret + +SemReleasex86 ENDP - .CODE +;;; Atomic functions ;;;--------------------------------------------------------------------- ;;; PRInt32 _Optlink _PR_MD_ATOMIC_SET(PRInt32* val, PRInt32 newval) ;;;--------------------------------------------------------------------- -_PR_MD_ATOMIC_SET PROC OPTLINK EXPORT - lock xchg dword ptr [eax],edx +_PR_MD_ATOMIC_SET proc + lock xchg dword ptr [eax],edx mov eax, edx; ret @@ -52,7 +290,7 @@ _PR_MD_ATOMIC_SET endp ;;;--------------------------------------------------------------------- ;;; PRInt32 _Optlink _PR_MD_ATOMIC_ADD(PRInt32* ptr, PRInt32 val) ;;;--------------------------------------------------------------------- -_PR_MD_ATOMIC_ADD PROC OPTLINK EXPORT +_PR_MD_ATOMIC_ADD proc mov ecx, edx lock xadd dword ptr [eax], edx mov eax, edx @@ -64,7 +302,7 @@ _PR_MD_ATOMIC_ADD endp ;;;--------------------------------------------------------------------- ;;; PRInt32 _Optlink _PR_MD_ATOMIC_INCREMENT(PRInt32* val) ;;;--------------------------------------------------------------------- -_PR_MD_ATOMIC_INCREMENT PROC OPTLINK EXPORT +_PR_MD_ATOMIC_INCREMENT proc mov edx, 1 lock xadd dword ptr [eax], edx mov eax, edx @@ -76,7 +314,7 @@ _PR_MD_ATOMIC_INCREMENT endp ;;;--------------------------------------------------------------------- ;;; PRInt32 _Optlink _PR_MD_ATOMIC_DECREMENT(PRInt32* val) ;;;--------------------------------------------------------------------- -_PR_MD_ATOMIC_DECREMENT PROC OPTLINK EXPORT +_PR_MD_ATOMIC_DECREMENT proc mov edx, 0ffffffffh lock xadd dword ptr [eax], edx mov eax, edx @@ -85,4 +323,5 @@ _PR_MD_ATOMIC_DECREMENT PROC OPTLINK EXPORT ret _PR_MD_ATOMIC_DECREMENT endp - END +CODE32 ENDS +END |