Tvùrce webu je i pro tebe! Postav tøeba web. Bez grafika. Bez kodéra. Hned.
wz

SEMAPHOR.ASM

Semaphore and Mutex


; =============================================================================
;
;                          Litos - Semaphore and mutex
;
; =============================================================================

		CODE_SECTION	32

; ------------- Macro - initialized semaphore (%1 = counter, usually 1)

%macro		SEMAPHORE 1
		TLOCK			; task lock
		dd	%1		; counter
		dd	0		; no sleepers
%endmacro

; ------------- Macro - initialized mutex

%macro		MUTEX 0
		SEMAPHORE SEM_UNLOCKED	; semaphore
		dd	0		; owner
		dd	0		; recursion counter
%endmacro

; ------------- Macro - initialize semaphore (%1=pointer, %2=counter)

%macro		SEM_Init 2

		TLOCK_Init %1		; initialize task lock
		mov	dword [%1+SEM_Count],%2 ; set counter
		and	dword [%1+SEM_Sleepers],byte 0 ; clear sleepers flag
%endmacro

; ------------- Macro - initialize mutex (%1=pointer)

%macro		MUTEX_Init 1

		push	eax		; push EAX
		xor	eax,eax		; EAX <- 0
		mov	[%1+SEM_Sleepers],eax ; clear sleepers flag
		mov	[%1+SEM_Owner],eax ; clear owner
		mov	[%1+SEM_Recursion],eax ; recursion counter
		inc	eax		; EAX <- 1
		mov	dword [%1+SEM_Count],eax ; set counter to 1
		TLOCK1_Init %1		; initialize task lock
		pop	eax		; pop EAX
%endmacro

; -----------------------------------------------------------------------------
;                           Initialize semaphore
; -----------------------------------------------------------------------------
; INPUT:	EAX = initial counter
;		EBX = pointer to semaphore SEM
; -----------------------------------------------------------------------------

SemInit:	SEM_Init ebx,eax	; initialize semaphore
		ret

; -----------------------------------------------------------------------------
;                           Initialize mutex
; -----------------------------------------------------------------------------
; INPUT:	EBX = pointer to mutex MUT
; -----------------------------------------------------------------------------

MutexInit:	MUTEX_Init ebx		; initialize mutex
		ret

; -----------------------------------------------------------------------------
;                    Semaphore down callback function
; -----------------------------------------------------------------------------
; INPUT:	EBX = pointer to semaphore SEM
;		EDX = 1 on first passage else 0
; OUTPUT:	AL = 0: sleep and wait for resource become free
;		AL = 1: resource successfully locked
;		EDX = 0
; -----------------------------------------------------------------------------

; ------------- Get sleepers and add undo of my lock (only in first passage)

SemDownCB:	mov	eax,[ebx+SEM_Sleepers] ; 1=any sleeper, 0=no sleeper
		add	eax,edx		; EAX <- 0, 1, 2 (sleepers + my undo)
		xor	edx,edx		; EDX <- 0, no other undo

; ------------- Count other sleepers to lock counter

		dec	eax		; other sleepers + my lock
%ifdef	SMP
		lock			; CPU instruction lock
%endif
		add	[ebx+SEM_Count],eax ; add other sleepers and test
		js	SemDownCB4	; lock not caught

; ------------- We have caught the semaphore, stop waiting

		xor	eax,eax		; EAX <- 0
		mov	[ebx+SEM_Sleepers],eax ; clear sleeper flag
		inc	eax		; EAX <- 1, continue flag
		ret

; ------------- We continue waiting

SemDownCB4:	xor	eax,eax		; EAX <- 0
		inc	eax		; EAX <- 1
		mov	[ebx+SEM_Sleepers],eax ; mark that any task is waiting
		dec	eax		; EAX <- 0, go to sleep flag
		ret

; -----------------------------------------------------------------------------
;                       Semaphore down (lock semaphore)
; -----------------------------------------------------------------------------
; INPUT:	EBX = pointer to semaphore SEM
; -----------------------------------------------------------------------------

; ------------- Try to lock semaphore

SemDown:
%ifdef	SMP
		lock			; CPU instruction lock
%endif
		dec	dword [ebx+SEM_Count] ; decrease counter
		js	SemDown2	; semaphore is already locked
		ret

; ------------- Push registers

SemDown2:       push	eax		; push EAX
		push	ecx		; push ECX
		push	edx		; push EDX

; ------------- Prepare flag to undo my try to lock (-> EDX)

		xor	edx,edx		; EDX <- 0
		inc	edx		; EDX <- 1, flag of first passage

; ------------- Lock semaphore

		xor	eax,eax		; EAX <- 0
		dec	eax		; EAX <- -1, infinitely wait
		mov	ecx,SemDownCB	; ECX <- lock semaphore callback
		call	TaskSleepFnc	; lock semaphore

; ------------- Pop registers

		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                 Try to semaphore down callback function
; -----------------------------------------------------------------------------
; INPUT:	EBX = pointer to semaphore SEM
; OUTPUT:	AL = 0: semaphore not cautch
;		AL = 1: semaphore can be locked, wake-up next task
; -----------------------------------------------------------------------------

; ------------- Clear sleepers

SemTryDownCB:	xor	eax,eax		; EAX <- 0, no other sleeper
		xchg	eax,[ebx+SEM_Sleepers] ; EAX <- 1=any other sleeper

; ------------- Add sleepers (and undo my lock) into counter

		inc	eax		; EAX <- sleepers include my lock
%ifdef	SMP
		lock			; CPU instruction lock
%endif
		add	[ebx+SEM_Count],eax ; add other sleepers and test
		setns	al		; AL <- 1 sem is free, 0 not free
		ret

; -----------------------------------------------------------------------------
;                  Try to semaphore down (lock semaphore)
; -----------------------------------------------------------------------------
; INPUT:	EBX = pointer to semaphore SEM
; OUTPUT:	CY = error, semaphore already locked
;		NC = OK, semaphore successfully locked
; -----------------------------------------------------------------------------

; ------------- Try to lock semaphore

SemTryDown:
%ifdef	SMP
		lock			; CPU instruction lock
%endif
		dec	dword [ebx+SEM_Count] ; decrease counter
		js	SemTryDown2	; semaphore is already locked
		clc			; clear error flag, we caught the lock
		ret

; ------------- Push registers

SemTryDown2:	push	ecx		; push ECX

; ------------- Undo semaphore lock

		mov	ecx,SemTryDownCB ; ECX <- try lock semaphore callback
		call	TaskWakeUpFnc	; unlock semaphore

; ------------- Pop registers

		pop	ecx		; pop ECX
		stc			; set error flag, we have not semaphore
		ret

; -----------------------------------------------------------------------------
;                    Semaphore up (unlock semaphore)
; -----------------------------------------------------------------------------
; INPUT:	EBX = pointer to semaphore SEM
; -----------------------------------------------------------------------------

SemUp:	
%ifdef	SMP
		lock			; CPU instruction lock
%endif
		inc	dword [ebx+SEM_Count] ; increase counter
		jle	near TaskWakeUp	; other task was waiting
		ret			; nobody waits for semaphore

; -----------------------------------------------------------------------------
;                    Lock mutext callback function
; -----------------------------------------------------------------------------
; INPUT:	EBX = pointer to mutex MUT
;		EDX = 1: first passage, else 0
; OUTPUT:	EAX = 0: sleep and wait for resource become free
;		EAX = 1: resource successfully locked
;		EDX = 0, not first passage
; -----------------------------------------------------------------------------

; ------------- Get sleepers and add undo of my lock (only in first passage)

MutexLockCB:	mov	eax,[ebx+SEM_Sleepers] ; 1=any sleeper, 0=no sleeper
		add	eax,edx		; EAX <- 0, 1, 2 (sleepers + my undo)
		xor	edx,edx		; EDX <- 0, no other undo

; ------------- Count other sleepers to lock counter

		dec	eax		; other sleepers without me
%ifdef	SMP
		lock			; CPU instruction lock
%endif
		add	[ebx+SEM_Count],eax ; add other sleepers and test
		js	MutexLockCB4	; lock not caught

; ------------- We have caught the mutex, stop waiting

		CURRENT	eax		; EAX <- current task
		mov	[ebx+SEM_Owner],eax ; set owner of mutex
		xor	eax,eax		; EAX <- 0
		mov	[ebx+SEM_Sleepers],eax ; clear sleeper flag
		inc	eax		; EAX <- 1, continue flag
		mov	[ebx+SEM_Recursion],eax ; set recursion counter to 1
		ret

; ------------- We continue waiting

MutexLockCB4:	xor	eax,eax		; EAX <- 0
		inc	eax		; EAX <- 1
		mov	[ebx+SEM_Sleepers],eax ; mark that any task is waiting
		dec	eax		; EAX <- 0, go to sleep flag
		ret

; -----------------------------------------------------------------------------
;                             Lock mutex
; -----------------------------------------------------------------------------
; INPUT:	EBX = pointer to mutex MUT
; -----------------------------------------------------------------------------

; ------------- Push registers

MutexLock: 	push	eax		; push EAX

; ------------- Prepare current task (-> EAX)

		CURRENT	eax		; EAX <- current task

; ------------- Try to lock mutex
%ifdef	SMP
		lock			; CPU instruction lock
%endif
		dec	dword [ebx+SEM_Count] ; decrease counter
		js	MutexLock2	; mutex is already locked

; ------------- Set owner of mutex

		mov	[ebx+SEM_Owner],eax ; set owner of mutex
		xor	eax,eax		; EAX <- 0
		inc	eax		; EAX <- 1
		mov	[ebx+SEM_Recursion],eax ; set recursion counter

; ------------- Pop registers

		pop	eax		; pop EAX
		ret

; ------------- Check if mutex is locked by this task

MutexLock2:	cmp	eax,[ebx+SEM_Owner] ; we already own the lock?
		jne	MutexLock4	; we have not the lock

; ------------- Increase recursion counter

		inc	dword [ebx+SEM_Recursion] ; increase recursion counter

; ------------- Pop registers

		pop	eax		; pop EAX
		ret

; ------------- Push registers

MutexLock4:	push	ecx		; push ECX
		push	edx		; push EDX

; ------------- Prepare flag to undo my try to lock (-> EDX)

		xor	edx,edx		; EDX <- 0
		inc	edx		; EDX <- 1, flag of first passage

; ------------- Lock mutex

		xor	eax,eax		; EAX <- 0
		dec	eax		; EAX <- -1, infinitely wait
		mov	ecx,MutexLockCB	; ECX <- lock mutex callback
		call	TaskSleepFnc	; lock mutex

; ------------- Pop registers

		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                    Try to lock mutex callback function
; -----------------------------------------------------------------------------
; INPUT:	EBX = pointer to mutex MUT
; OUTPUT:	AL = 0: mutex not cautch
;		AL = 1: mutex can be locked, wake-up next task
; -----------------------------------------------------------------------------

; ------------- Clear sleepers

MutexTryLockCB:	xor	eax,eax		; EAX <- 0, no other sleeper
		xchg	eax,[ebx+SEM_Sleepers] ; EAX <- 1=any other sleeper

; ------------- Add sleepers (and undo my lock) into counter

		inc	eax		; EAX <- sleepers include my lock
%ifdef	SMP
		lock			; CPU instruction lock
%endif
		add	[ebx+SEM_Count],eax ; add other sleepers and test
		setns	al		; AL <- 1 sem is free, 0 not free
		ret

; -----------------------------------------------------------------------------
;                         Try to lock mutex
; -----------------------------------------------------------------------------
; INPUT:	EBX = pointer to mutex MUT
; OUTPUT:	CY = error, mutex already locked
;		NC = OK, mutex successfully locked
; -----------------------------------------------------------------------------

; ------------- Push registers

MutexTryLock:	push	ecx		; push ECX

; ------------- Prepare current task (-> ECX)

		CURRENT	ecx		; ECX <- current task

; ------------- Try to lock mutex
%ifdef	SMP
		lock			; CPU instruction lock
%endif
		dec	dword [ebx+SEM_Count] ; decrease counter
		js	MutexTryLock2	; mutex is already locked

; ------------- Set owner of mutex

		mov	[ebx+SEM_Owner],ecx ; set owner of mutex
		xor	ecx,ecx		; ECX <- 0
		inc	ecx		; ECX <- 1
		mov	[ebx+SEM_Recursion],ecx ; set recursion counter

; ------------- Pop registers (here is NC)

		pop	ecx		; pop ECX
		ret

; ------------- Check if mutex is locked by this task

MutexTryLock2:	cmp	ecx,[ebx+SEM_Owner] ; we already own the lock?
		jne	MutexTryLock4	; we have not the lock

; ------------- Increase recursion counter

		inc	dword [ebx+SEM_Recursion] ; increase recursion counter

; ------------- Pop registers (here is NC)

		pop	ecx		; pop ECX
		ret      

; ------------- Undo mutex lock

MutexTryLock4:	mov	ecx,MutexTryLockCB ; ECX <- try lock mutex callback
		call	TaskWakeUpFnc	; unlock mutex

; ------------- Pop registers

		pop	ecx		; pop ECX
		stc			; set error flag, we have not mutex
		ret

; -----------------------------------------------------------------------------
;                           Unlock mutex
; -----------------------------------------------------------------------------
; INPUT:	EBX = pointer to mutex MUT
; -----------------------------------------------------------------------------

; ------------- Decrease recursion counter

MutexUnlock:	dec 	dword [ebx+SEM_Recursion] ; decrease recursion
		jnz	MutexUnlock4	; it is not last recursion

; ------------- Reset owner of mutex

		and	dword [ebx+SEM_Owner],byte 0 ; clear owner

; ------------- Last recursion, unlock mutex and switch to another task
%ifdef	SMP
		lock			; CPU instruction lock
%endif
		inc	dword [ebx+SEM_Count] ; increase counter
		jle	near TaskWakeUp	; other task was waiting
		ret			; nobody waits for mutex

; ------------- Not last recursion, only unlock mutex

MutexUnlock4:
%ifdef	SMP
		lock			; CPU instruction lock
%endif
		inc	dword [ebx+SEM_Count] ; increase counter
		ret			; nobody waits for mutex

Back to source browser