summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorseawood%netscape.com <devnull@localhost>2002-02-16 02:25:51 +0000
committerseawood%netscape.com <devnull@localhost>2002-02-16 02:25:51 +0000
commitb93c63183e29aa6c14e2d95015eda2aec9f0671b (patch)
tree6ff135c4fb6cb82fd50b96011bb60cb7e3be6634
parent5cc970ff507fb34535ca3b7f706f45434de462fd (diff)
downloadnspr-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.h33
-rw-r--r--pr/src/md/os2/os2cv.c95
-rw-r--r--pr/src/md/os2/os2vacpp.asm259
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