; =============================================================================
;
; Litos - Signals
;
; =============================================================================
; TODO: Verify destination task. Verify access rights (user).
; TODO: Signal handler
CODE_SECTION 32
GET eax,1234h,5678h ; only test, delete it later
; -----------------------------------------------------------------------------
; Set signal context in user stack
; -----------------------------------------------------------------------------
; INPUT:
; -----------------------------------------------------------------------------
SignalSetCont: ; !!!!!!! TODO
ret
; -----------------------------------------------------------------------------
; Service signal
; -----------------------------------------------------------------------------
; OUTPUT: CY = task killed
; -----------------------------------------------------------------------------
; TODO: Wake-up sleeping tasks is any signal is pending.
; ------------- Push registers
DoSignal: pusha ; push all registers
mov ebp,esp ; EBP <- push stack pointer
; ------------- Prepare local SIGINFO buffer for signal (-> ECX)
sub esp,byte SIGINFO_size ; create SIGINFO buffer
mov ecx,esp ; ECX <- SIGINFO buffer
; ------------- Get current task (-> EBX)
CURRENT ebx ; EBX <- get current task
; ------------- Get next signal (into ECX buffer)
DoSignal2: call SignalNext ; get next signal
jc near DoSignal8 ; no next signal
; ------------- Get and lock signal action table (-> EDX)
mov edx,[ebx+TASK_SigAction] ; EDX <- signal action table
%ifdef SMP
call SpinLockEDX ; lock signal action table
%endif
; ------------- Get signal action (-> ESI) and handler (-> EDI)
movzx eax,byte [ecx+SI_Signal] ; EAX <- signal number
shl eax,1 ; EAX <- signal number * 2
lea esi,[edx+eax*(SIGACT_size/2)] ; ESI <- action table
mov edi,[esi+SA_Handler] ; EDI <- handler
; ------------- Use parent's signal
cmp edi,byte SA_PAR ; use parent's signal?
jne DoSignal28
push ebx ; push EBX
push edx ; push EDX
DoSignal22: add edi,byte SA_IGN-SA_PAR ; EDI <- ignore signal
mov ebx,[ebx+TASK_Link+TREE_Parent] ; EBX <- parent
or ebx,ebx ; valid parent?
jz DoSignal24 ; parent is not valid
mov edx,[ebx+TASK_SigAction] ; EDX <- signal action table
lea edx,[edx+eax*(SIGACT_size/2)] ; EDX <- action table
mov edi,[edx+SA_Handler] ; EDI <- handler
cmp edi,byte SA_PAR ; use parent's signal?
je DoSignal22 ; use parent's signal
DoSignal24: pop edx ; pop EDX
pop ebx ; pop EBX
; ------------- 0: SA_DEF, Default action
DoSignal28: or edi,edi ; default action?
jnz DoSignal3 ; no default action
or edi,byte SA_TERM ; EDI <- terminate
cmp al,32 ; real-time signal?
jae DoSignal3 ; real-time signal
movzx edi,byte [SignalDefAct+eax] ; EDI <- default action
; ------------- 1: SA_IGN, Ignore signal
DoSignal3: dec edi ; signal action - 1
jnz DoSignal32 ; don't ignore signal
DoSignal31:
%ifdef SMP
LOCK_Unlock edx ; unlock signal action table
%endif
jmp short DoSignal2 ; get next signal
; ------------- 2: SA_TERM, Terminate the process
DoSignal32: dec edi ; terminate the process?
jnz DoSignal34 ; don't terminate the process
DoSignal33:
%ifdef SMP
LOCK_Unlock edx ; unlock signal action table
%endif
call TaskKill ; kill the task
stc ; error flag - task killed
jmp short DoSignal9
; ------------- 3: SA_DUMP, Terminate and dump
DoSignal34: dec edi ; terminate and dump?
jnz DoSignal36 ; don't terminate and dump
; !!!!!!! TODO
jmp short DoSignal33
; ------------- 4: SA_STOP, Stop the task
DoSignal36: dec edi ; stop the task
jnz DoSignal4 ; dont stop the task
%ifdef SMP
LOCK_Unlock edx ; unlock signal action table
%endif
call TaskStop ; stop task
jmp DoSignal2 ; get next signal
; ------------- User handler
DoSignal4: add edi,byte 4 ; EDI <- handler
; !!!!!!! TODO
%ifdef SMP
LOCK_Unlock edx ; unlock signal action table
%endif
jmp DoSignal2 ; get next signal
; ------------- Pop registers
DoSignal8: clc
DoSignal9: mov esp,ebp ; ESP <- pop stack pointer
popa ; pop all registers
ret
; -----------------------------------------------------------------------------
; Test if ignore signal
; -----------------------------------------------------------------------------
; INPUT: AL = signal number
; EDX = destination task
; OUTPUT: CY = ignore signal
; NOTES: Blocked or traced signals are not ignored.
; -----------------------------------------------------------------------------
; ------------- Push registers
SignalTestIgn: push eax ; push EAX
push ebx ; push EBX
; ------------- Check signal number
cmp al,SIGNULL ; unused signal
je SignalTestIgn7 ; signal is always ignored
cmp al,63 ; maximal signal number
ja SignalTestIgn7 ; ignore invalid signal number
; ------------- Check if task is traced (signal cannot be ignored)
test byte [edx+TASK_Trace],PTRACED ; is task traced?
jnz SignalTestIgn8 ; signal cannot be ignored if traced
; ------------- Blocked signals are not ignored (signal handler may change)
movzx eax,al ; EAX <- signal number
bt [edx+TASK_SigMask],eax ; test signal mask (CY=enabled)
jnc SignalTestIgn8 ; signal is blocked, don't ignore it
; ------------- Pointer to signal action (-> EBX)
shl eax,1 ; EAX <- signal number * 2
mov ebx,[edx+TASK_SigAction] ; EBX <- action table
lea ebx,[ebx+eax*(SIGACT_size/2)] ; EBX <- action table
; ------------- Ignore signal (= 1, SIG_IGN)
mov ebx,[ebx+SA_Handler] ; get signal handler
dec ebx ; ignore signal (=1) ?
jz SignalTestIgn7 ; ignore signal
; ------------- Default handler (= 0, SIG_DFL)
inc ebx ; default handler?
clc ; flag "don't ignore"
jnz SignalTestIgn8 ; no default handler, not ignored
; ------------- Check if default ignore signal
cmp al,SIGCHLD*2 ; child notify?
je SignalTestIgn7 ; ignore child notify
cmp al,SIGWINCH*2 ; change windows size?
je SignalTestIgn7 ; ignore change window size
cmp al,SIGURG*2 ; urgent condition on socket?
clc ; preset flag - don't ignore
jne SignalTestIgn8 ; another signal, don't ignore it
SignalTestIgn7: stc ; CY <- set flag "ignore signal"
; ------------- Pop registers
SignalTestIgn8: pop ebx ; pop EBX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Flush STOP pending signals for destination task
; -----------------------------------------------------------------------------
; INPUT: EDX = destination task
; NOTES: Signal queue must be locked and interrupts disabled.
; Stop signals are: SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU.
; -----------------------------------------------------------------------------
%define STOP_MASK ( (1<<SIGSTOP) | (1<<SIGTSTP) | (1<<SIGTTIN) | (1<<SIGTTOU) )
; ------------- Check if any STOP is pending
SigFlushStop: test dword [edx+TASK_Signal],STOP_MASK
jz SigFlushStop9 ; no pending signal
; ------------- Push registers
push eax ; push EAX
push ebx ; push EBX
push ecx ; push ECX
; ------------- Find STOP signals
lea ebx,[edx+TASK_SigQueue] ; EBX <- head
mov ecx,ebx ; ECX <- queue head
SigFlushStop2: mov ebx,[ebx+LIST_Next] ; EBX <- next item
SigFlushStop4: cmp ebx,ecx ; end of queue?
je SigFlushStop8 ; end of queue
; ------------- Check signal
movzx eax,byte [ebx+SIGNAL_Info+SI_Signal] ; signal number
cmp al,SIGSTOP ; SIGSTOP signal?
je SigFlushStop6 ; yes, SIGSTOP
cmp al,SIGTSTP ; SIGTSTP signal?
je SigFlushStop6 ; yes, SIGTSTP
cmp al,SIGTTIN ; SIGTTIN signal?
je SigFlushStop6 ; yes, SIGTTIN
cmp al,SIGTTOU ; SIGTTOU signal?
jne SigFlushStop2 ; no
; ------------- Decrease number of signals and reset signal flag
SigFlushStop6: dec dword [ecx+TASK_SigNum-TASK_SigQueue]; decrease signals
btr [ecx+TASK_Signal-TASK_SigQueue],eax ; reset flag
; ------------- Free old entry from the queue
xchg eax,ebx ; EAX <- signal item
mov ebx,[eax+LIST_Next] ; EBX <- next item
call ListDel ; free signal list entry
call SysMemFree ; free memory block
jmp short SigFlushStop4
; ------------- Pop registers
SigFlushStop8: pop ecx ; pop ECX
pop ebx ; pop EBX
pop eax ; pop EAX
SigFlushStop9: ret
; -----------------------------------------------------------------------------
; Send signal info to a task
; -----------------------------------------------------------------------------
; INPUT: ECX = filled SIGINFO structure (its content will be copied)
; EDX = destination task (must be valid)
; OUTPUT: CY = error, signal cannot be sent (queue full or memory error)
; LOCKS: TASK_SigLock, SysMemLock
; NOTES: Regular signals (0 to 31) are not limited to queue size.
; Sender entry will be filled with current running task.
; -----------------------------------------------------------------------------
; TODO: Wake-up sleeping tasks is any signal is pending.
; ------------- Ignore signal (-> EAX = signal number)
SignalSendInfo: push eax ; push EAX
movzx eax,byte [ecx+SI_Signal] ; EAX <- signal number
call SignalTestIgn ; test if ignore signal
jnc SignalSendInfo1 ; signal not ignored
pop eax ; pop EAX
clc ; clear error flag
ret
; ------------- Push registers
SignalSendInfo1:push ebx ; push EBX
push edx ; push EDX
pushf ; push flags
cli ; disable interrupts
; ------------- Lock signal queue (-> EDX = signal queue lock)
add edx,TASK_SigLock ; EDX <- signal queue lock
%ifdef SMP
LOCK_Lock edx ; lock signal queue
%endif
; ------------- For SIGCONT flush pending STOP signals
cmp al,SIGCONT ; SIGCONT signal?
jne SignalSendInf14 ; no
sub edx,TASK_SigLock ; EDX <- task
call SigFlushStop ; flush STOP signals
; ------------- Unlock signal queue list
mov ebx,edx ; EBX <- task
add edx,TASK_SigLock ; EDX <- signal queue lock
%ifdef SMP
LOCK_Unlock edx ; unlock queue
%endif
; ------------- Service SIGCONT signal
call TaskContinue ; continue the task
jmp SignalSendInf74
; ------------- Check if it is regular signal
SignalSendInf14:cmp al,32 ; is it regular signal?
jae SignalSendInfo3 ; no, it is real-time signal
; ------------- Check if signal is already in the queue list
bt [edx+TASK_Signal-TASK_SigLock],eax ; signal in queue?
jnc SignalSendInfo5 ; signal is not in the queue
; ------------- Find this signal in the signal queue list
lea ebx,[edx+TASK_SigQueue-TASK_SigLock] ; EBX<-queue list
SignalSendInfo2:mov ebx,[ebx+LIST_Next] ; EBX <- next item
cmp [ebx+SIGNAL_Info+SI_Signal],al ; signal found?
jne SignalSendInfo2 ; no, try next item
; ------------- Free signal list entry from the queue
call ListDelEBX ; free signal list entry
dec dword [edx+TASK_SigNum-TASK_SigLock]; decrease entries
jmp short SignalSendInfo6 ; fill list entry
; ------------- Check number of signals (only for real-time signals)
SignalSendInfo3:cmp byte [edx+TASK_SigRTNum-TASK_SigLock+eax-32],255; full?
je SignalSendInfo4 ; signal queue is full
mov ebx,[edx+TASK_SigNum-TASK_SigLock] ; EBX <- signals
cmp ebx,[edx+TASK_SigMax-TASK_SigLock] ; max. signals?
jb SignalSendInfo5 ; signal queue is not full
; ------------- Unlock signal queue list on ERROR (-> CY)
SignalSendInfo4:
%ifdef SMP
LOCK_Unlock edx ; unlock signal queue
%endif
; ------------- Set error flag
popf ; pop flags
stc ; set CF = error
jmp short SignalSendInfo9
; ------------- Create new signal queue item (-> EBX)
SignalSendInfo5:mov ebx,eax ; EBX <- push EAX (signal number)
mov al,SIGNAL_size ; EAX <- size of signal queue item
call SysMemAlloc ; get signal queue item
xchg eax,ebx ; pop EAX, EBX <- signal queue item
jnc SignalSendInfo6 ; item created OK
; ------------- For SIGKILL take reserved item (-> EBX)
cmp al,SIGKILL ; is it SIGKILL?
jne SignalSendInfo4 ; error
xor ebx,ebx ; EBX <- 0
xchg ebx,[edx+TASK_SigRes-TASK_SigLock] ; reserved item
or ebx,ebx ; is item valid?
jz SignalSendInfo4 ; error
; ------------- Copy signal info (into entry in EBX)
SignalSendInfo6:push eax ; push EAX (signal number)
mov eax,[ecx+SI_Signal] ; byte parameters
mov [ebx+SIGNAL_Info+SI_Signal],eax
CURRENT eax ; EAX <- get current task
mov [ebx+SIGNAL_Info+SI_Sender],eax
mov eax,[ecx+SI_Param1] ; parameter 1
mov [ebx+SIGNAL_Info+SI_Param1],eax
mov eax,[ecx+SI_Param2] ; parameter 2
mov [ebx+SIGNAL_Info+SI_Param2],eax
mov eax,[ecx+SI_Param3] ; parameter 3
mov [ebx+SIGNAL_Info+SI_Param3],eax
mov eax,[ecx+SI_Param4] ; parameter 4
mov [ebx+SIGNAL_Info+SI_Param4],eax
; ------------- Add new entry into signal queue list
xchg eax,ebx ; EAX <- signal queue item
lea ebx,[edx+TASK_SigQueue-TASK_SigLock]; signal queue list
call ListLast ; add item at end of list
pop eax ; pop EAX (signal number)
; ------------- Set signal flag and count signal number
bts [edx+TASK_Signal-TASK_SigLock],eax ; set signal flag
inc dword [edx+TASK_SigNum-TASK_SigLock] ; increase entries
cmp al,32 ; is it regular signal?
jb SignalSendInfo7 ; it is regular signal
inc byte [edx+TASK_SigRTNum-TASK_SigLock+eax-32]
; ------------- Unlock signal queue list on OK (-> NC)
SignalSendInfo7:
%ifdef SMP
LOCK_Unlock edx ; unlock queue
%endif
; ------------- Reschedule task if signal is not blocked
bt [edx+TASK_SigMask-TASK_SigLock],eax ; signal blocked?
jnc SignalSendInfo8 ; signal is blocked
SignalSendInf74:mov ebx,[edx+TASK_RunQueue-TASK_SigLock] ; run-queue
RESCHEDULE ebx ; reschedule request
; ------------- Pop registers
SignalSendInfo8:popf ; pop flags
clc ; clear CF = operation OK
SignalSendInfo9:pop edx ; pop EDX
pop ebx ; pop EBX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Send signal to a task
; -----------------------------------------------------------------------------
; INPUT: AL = signal number (0 to 63)
; EDX = destination task (must be valid)
; OUTPUT: CY = error, signal cannot be sent (queue full or memory error)
; -----------------------------------------------------------------------------
; ------------- Push registers
SignalSend: push eax ; push EAX
push ecx ; push ECX
push ebp ; push EBP
mov ebp,esp ; EBP <- push stack pointer
; ------------- Create signal info structure
sub esp,byte SIGINFO_size; create buffer (must be aligned!)
mov ecx,esp ; ECX <- info structure
; ------------- Fill up signal info structure
movzx eax,al ; EAX <- signal number
mov [ecx+SI_SignalDW],eax ; byte parameters
xor eax,eax ; EAX <- 0
mov [ecx+SI_Param1],eax ; parameter 1
mov [ecx+SI_Param2],eax ; parameter 2
mov [ecx+SI_Param3],eax ; parameter 3
mov [ecx+SI_Param4],eax ; parameter 4
; ------------- Send signal info
call SignalSendInfo ; send signal info
; ------------- Pop registers
mov esp,ebp ; ESP <- pop stack pointer
pop ebp ; pop EBP
pop ecx ; pop ECX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Check if signal is pending in the signal queue (from user)
; -----------------------------------------------------------------------------
; INPUT: AL = signal number (0 to 63, except SIGKILL, SIGCONT, SIGSTOP)
; OUTPUT: CY = required signal is not pending
; NOTES: Signal may be pending even if it is blocked.
; -----------------------------------------------------------------------------
; ------------- Check signal number
SignalCheckU: cmp al,SIGKILL ; SIGKILL signal?
je SignalCheck2 ; forbidden signal
cmp al,SIGCONT ; SIGCONT signal?
je SignalCheck2 ; forbidden signal
cmp al,SIGSTOP ; SIGSTOP signal?
je SignalCheck2 ; forbidden signal
; SignalCheck must follow
; -----------------------------------------------------------------------------
; Check if signal is pending in the signal queue (from kernel)
; -----------------------------------------------------------------------------
; INPUT: AL = signal number (0 to 63)
; OUTPUT: CY = required signal is not pending
; NOTES: Signal may be pending even if it is blocked.
; -----------------------------------------------------------------------------
; ------------- Check signal number
SignalCheck: cmp al,64 ; check signal number
SignalCheck2: cmc
jc SignalCheck9 ; invalid signal
; ------------- Push registers
push eax ; push EAX
push ebx ; push EBX
; ------------- Get current task (-> EBX)
CURRENT ebx ; EBX <- get current task
; ------------- Check if signal is pending
movzx eax,al ; EAX <- signal number
bt [ebx+TASK_Signal],eax ; is signal pending?
cmc ; CY = signal is not pending
; ------------- Pop registers
pop ebx ; pop EBX
pop eax ; pop EAX
SignalCheck9: ret
; -----------------------------------------------------------------------------
; Get signal info from the signal queue (from user)
; -----------------------------------------------------------------------------
; INPUT: AL = signal number (0 to 63, except SIGKILL, SIGCONT, SIGSTOP)
; ECX = SIGINFO structure (it will be filled out with new data)
; OUTPUT: CY = required signal is not pending, structure will not change
; NC = signal removed from the signal queue and structure filled
; NOTES: Signal may be taken even if it is blocked.
; -----------------------------------------------------------------------------
; ------------- Check signal number
SignalGetInfoU: cmp al,SIGKILL ; SIGKILL signal?
je SignalGetInfo1 ; forbidden signal
cmp al,SIGCONT ; SIGCONT signal?
je SignalGetInfo1 ; forbidden signal
cmp al,SIGSTOP ; SIGSTOP signal?
je SignalGetInfo1 ; forbidden signal
; SignalGetInfo must follow
; -----------------------------------------------------------------------------
; Get signal info from the signal queue (from kernel)
; -----------------------------------------------------------------------------
; INPUT: AL = signal number (0 to 63)
; ECX = SIGINFO structure (it will be filled with new data)
; OUTPUT: CY = required signal is not pending, structure will not change
; NC = signal removed from the signal queue and structure filled
; NOTES: Signal may be taken even if it is blocked.
; -----------------------------------------------------------------------------
; ------------- Check signal number
SignalGetInfo: cmp al,64 ; check signal number
SignalGetInfo1: cmc ; complement error flag
jc near SignalGetInfo9 ; invalid signal
; ------------- Push registers
push eax ; push EAX
push ebx ; push EBX
; ------------- Get current task (-> EBX signal lock)
CURRENT ebx ; EBX <- get current task
add ebx,TASK_SigLock ; EBX <- signal queue lock
; ------------- Lock signal queue
pushf ; push flags
cli ; disable interrupts
%ifdef SMP
LOCK_Lock ebx ; lock signal queue
%endif
; ------------- Check if signal is pending
movzx eax,al ; EAX <- signal number
bt [ebx+TASK_Signal-TASK_SigLock],eax ; is signal pending?
jc SignalGetInfo2 ; signal is pending
; ------------- Unlock signal queue on ERROR
%ifdef SMP
LOCK_Unlock ebx ; unlock signal queue
%endif
popf ; pop flags
stc ; set error flag
jmp short SignalGetInfo8
; ------------- Decrease number of signals and reset signal flag
SignalGetInfo2: dec dword [ebx+TASK_SigNum-TASK_SigLock] ; decrease signals
cmp al,32 ; is it regular signal?
jb SignalGetInfo3 ; reset flag for regular signal
dec byte [ebx+TASK_SigRTNum-TASK_SigLock+eax-32]
jnz SignalGetInfo4 ; there are another real-time signals
SignalGetInfo3: btr [ebx+TASK_Signal-TASK_SigLock],eax ; reset flag
; ------------- Find the signal
SignalGetInfo4:
%ifdef SMP
push ebx ; push EBX (signal lock)
%endif
add ebx,byte TASK_SigQueue-TASK_SigLock ; EBX <- list head
SignalGetInfo5: mov ebx,[ebx+LIST_Next] ; EBX <- next item
cmp [ebx+SIGNAL_Info+SI_Signal],al ; signal found?
jne SignalGetInfo5 ; no, try next item
; ------------- Get signal parameters
mov eax,[ebx+SIGNAL_Info+SI_SignalDW] ; byte parameters
mov [ecx+SI_SignalDW],eax
mov eax,[ebx+SIGNAL_Info+SI_Sender] ; sender
mov [ecx+SI_Sender],eax
mov eax,[ebx+SIGNAL_Info+SI_Param1] ; parameter 1
mov [ecx+SI_Param1],eax
mov eax,[ebx+SIGNAL_Info+SI_Param2] ; parameter 2
mov [ecx+SI_Param2],eax
mov eax,[ebx+SIGNAL_Info+SI_Param3] ; parameter 3
mov [ecx+SI_Param3],eax
mov eax,[ebx+SIGNAL_Info+SI_Param4] ; parameter 4
mov [ecx+SI_Param4],eax
; ------------- Free old entry from the queue
xchg eax,ebx ; EAX <- signal entry
call ListDel ; free signal list entry
call SysMemFree ; free memory block
; ------------- Unlock signal queue on OK
%ifdef SMP
pop ebx ; pop EBX (signal lock)
LOCK_Unlock ebx ; unlock signal queue
%endif
popf ; pop flags
clc ; clear error flag, operation OK
; ------------- Pop registers
SignalGetInfo8: pop ebx ; pop EBX
pop eax ; pop EAX
SignalGetInfo9: ret
; -----------------------------------------------------------------------------
; Get specific signal from the signal queue (from user)
; -----------------------------------------------------------------------------
; INPUT: AL = signal number (0 to 63, except SIGKILL, SIGCONT, SIGSTOP)
; OUTPUT: CY = required signal is not pending
; NC = signal found and removed from the signal queue
; NOTES: Signal may be taken even if it is blocked.
; -----------------------------------------------------------------------------
; ------------- Push registers
SignalGetU: push ecx ; push ECX
push ebp ; push EBP
mov ebp,esp ; EBP <- push stack pointer
; ------------- Create signal info structure
sub esp,byte SIGINFO_size; create buffer (must be aligned!)
mov ecx,esp ; ECX <- info structure
; ------------- Get signal info
call SignalGetInfoU ; get signal info
; ------------- Pop registers
mov esp,ebp ; ESP <- pop stack pointer
pop ebp ; pop EBP
pop ecx ; pop ECX
ret
; -----------------------------------------------------------------------------
; Get specific signal from the signal queue (from kernel)
; -----------------------------------------------------------------------------
; INPUT: AL = signal number (0 to 63)
; OUTPUT: CY = required signal is not pending
; NC = signal found and removed from the signal queue
; NOTES: Signal may be taken even if it is blocked.
; -----------------------------------------------------------------------------
; ------------- Push registers
SignalGet: push ecx ; push ECX
push ebp ; push EBP
mov ebp,esp ; EBP <- push stack pointer
; ------------- Create signal info structure
sub esp,byte SIGINFO_size; create buffer (must be aligned!)
mov ecx,esp ; ECX <- info structure
; ------------- Get signal info
call SignalGetInfo ; get signal info
; ------------- Pop registers
mov esp,ebp ; ESP <- pop stack pointer
pop ebp ; pop EBP
pop ecx ; pop ECX
ret
; -----------------------------------------------------------------------------
; Get next unblocked signal from the signal queue
; -----------------------------------------------------------------------------
; INPUT: ECX = SIGINFO structure (it will be filled with new data)
; OUTPUT: CY = no unblocked signal is pending, structure will not change
; NC = signal removed from the queue and structure filled out
; -----------------------------------------------------------------------------
; ------------- Push registers
SignalNext: push eax ; push EAX
push ebx ; push EBX
push edx ; push EDX
; ------------- Get current task (-> EBX signal lock)
CURRENT ebx ; EBX <- get current task
add ebx,TASK_SigLock ; EBX <- signal queue lock
; ------------- Lock signal queue
pushf ; push flags
cli ; disable interrupts
%ifdef SMP
LOCK_Lock ebx ; lock signal queue
%endif
; ------------- Check if any signal is pending
mov eax,[ebx+TASK_SigMask-TASK_SigLock] ; EAX <- mask LOW
test eax,[ebx+TASK_Signal-TASK_SigLock] ; pending signal?
jnz SignalNext3 ; pending signal found
mov edx,[ebx+TASK_SigMask-TASK_SigLock+4]; EDX <- mask HIGH
test edx,[ebx+TASK_Signal-TASK_SigLock+4] ; pending signal?
jnz SignalNext3 ; pending signal found
; ------------- Unlock signal queue on ERROR
%ifdef SMP
LOCK_Unlock ebx ; unlock signal queue
%endif
popf ; pop flags
stc ; set error flag
jmp short SignalNext9
; ------------- Find signal (here is EDX:EAX=signal mask, EBX=queue lock)
SignalNext3: push ebx ; push EBX (signal lock)
push ecx ; push ECX (SIGINFO structure)
add ebx,byte TASK_SigQueue-TASK_SigLock ; EBX <- head
SignalNext4: mov ebx,[ebx+LIST_Next] ; EBX <- next item
movzx ecx,byte [ebx+SIGNAL_Info+SI_Signal] ; signal number
; ------------- Check signal LOW
cmp cl,32 ; is it signal LOW?
jae SignalNext5 ; it is signal HIGH
bt eax,ecx ; test if signal is blocked
jc SignalNext6 ; signal is not blocked
jmp short SignalNext4 ; try next signal
; ------------- Check signal HIGH
SignalNext5: sub cl,32 ; CL <- signal offset
bt edx,ecx ; test if signal is blocked
jnc SignalNext4 ; signal is blocked, try next one
; ------------- Get signal parameters
SignalNext6: pop ecx ; pop ECX (SIGINFO structure)
mov eax,[ebx+SIGNAL_Info+SI_Sender] ; sender
mov [ecx+SI_Sender],eax
mov eax,[ebx+SIGNAL_Info+SI_Param1] ; parameter 1
mov [ecx+SI_Param1],eax
mov eax,[ebx+SIGNAL_Info+SI_Param2] ; parameter 2
mov [ecx+SI_Param2],eax
mov eax,[ebx+SIGNAL_Info+SI_Param3] ; parameter 3
mov [ecx+SI_Param3],eax
mov eax,[ebx+SIGNAL_Info+SI_Param4] ; parameter 4
mov [ecx+SI_Param4],eax
mov eax,[ebx+SIGNAL_Info+SI_SignalDW] ; byte parameters
mov [ecx+SI_SignalDW],eax
movzx eax,al ; EAX <- signal number
; ------------- Free old entry from the queue
xchg eax,ebx ; EAX <- entry, EBX <- signal number
call ListDel ; free signal list entry
call SysMemFree ; free memory block
xchg eax,ebx ; EAX <- signal number
pop ebx ; pop EBX (signal queue lock)
; ------------- Decrease number of signals and reset signal flag
dec dword [ebx+TASK_SigNum-TASK_SigLock] ; decrease signals
cmp al,32 ; is it regular signal?
jb SignalNext7 ; reset flag for regular signal
dec byte [ebx+TASK_SigRTNum-TASK_SigLock+eax-32]
jnz SignalNext8 ; there are another real-time signals
SignalNext7: btr [ebx+TASK_Signal-TASK_SigLock],eax ; reset flag
; ------------- Unlock signal queue on OK
SignalNext8:
%ifdef SMP
LOCK_Unlock ebx ; unlock signal queue
%endif
popf ; pop flags
clc ; clear error flag, operation OK
; ------------- Pop registers
SignalNext9: pop edx ; pop EDX
pop ebx ; pop EBX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Flush pending signals (from user)
; -----------------------------------------------------------------------------
; INPUT: EDX:EAX = signal mask (1=flush signal)
; NOTES: Cannot flush signals SIGKILL, SIGCONT, SIGSTOP.
; Blocked signals are flushed too.
; -----------------------------------------------------------------------------
SignalFlushU: push eax ; push EAX
and eax,~((1<<SIGKILL)+(1<<SIGCONT)+(1<<SIGSTOP))
call SignalFlush ; flush pending signals
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Flush pending signals (from kernel)
; -----------------------------------------------------------------------------
; INPUT: EDX:EAX = signal mask (1=flush signal)
; NOTES: Blocked signals are flushed too.
; -----------------------------------------------------------------------------
; ------------- Push registers
SignalFlush: push eax ; push EAX
push ebx ; push EBX
push ecx ; push ECX
push esi ; push ESI
push edi ; push EDI
pushf ; push flags
cli ; disable interrupts
; ------------- Get current task (-> EBX signal lock)
CURRENT ebx ; EBX <- get current task
add ebx,TASK_SigLock ; EBX <- signal queue lock
; ------------- Check if any signal is pending
test eax,[ebx+TASK_Signal-TASK_SigLock]; signal pending LOW?
jnz SignalFlush1 ; any signal pending LOW
test edx,[ebx+TASK_Signal+4-TASK_SigLock] ; pending HIGH?
jz SignalFlushA ; no pending signal
; ------------- Lock signal queue
SignalFlush1:
%ifdef SMP
LOCK_Lock ebx ; lock signal queue
%endif
; ------------- Find signal
SignalFlush2: lea esi,[ebx+TASK_SigQueue-TASK_SigLock] ; ESI <- head
mov edi,esi ; EDI <- queue head
SignalFlush3: mov esi,[esi+LIST_Next] ; ESI <- next item
SignalFlush4: cmp esi,edi ; end of queue?
je SignalFlush9 ; end of queue
movzx ecx,byte [esi+SIGNAL_Info+SI_Signal] ; signal number
; ------------- Check signal LOW
cmp cl,32 ; is it signal LOW?
jae SignalFlush5 ; it is signal HIGH
bt eax,ecx ; test if it is required signal
jc SignalFlush6 ; it is required signal
jmp short SignalFlush3 ; try next signal
; ------------- Check signal HIGH
SignalFlush5: sub cl,32 ; CL <- signal offset
bt edx,ecx ; test if it is required signal
jnc SignalFlush3 ; try next signal
add cl,32 ; ECX <- signal number
; ------------- Decrease number of signals and reset signal flag
SignalFlush6: dec dword [ebx+TASK_SigNum-TASK_SigLock] ; decrease signals
cmp cl,32 ; is it regular signal?
jb SignalFlush7 ; reset flag for regular signal
dec byte [ebx+TASK_SigRTNum-TASK_SigLock+ecx-32]
jnz SignalFlush8 ; there are another real-time signals
SignalFlush7: btr [ebx+TASK_Signal-TASK_SigLock],ecx ; reset flag
; ------------- Free old entry from the queue
SignalFlush8: push eax ; push EAX
xchg eax,esi ; EAX <- signal item
mov esi,[eax+LIST_Next] ; ESI <- next item
call ListDel ; free signal list entry
call SysMemFree ; free memory block
pop eax ; pop EAX
jmp short SignalFlush4
; ------------- Unlock signal queue
SignalFlush9:
%ifdef SMP
LOCK_Unlock ebx ; unlock signal queue
%endif
; ------------- Pop registers
SignalFlushA: popf ; pop flags
pop edi ; pop EDI
pop esi ; pop ESI
pop ecx ; pop ECX
pop ebx ; pop EBX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Flush all pending signals (from user)
; -----------------------------------------------------------------------------
; NOTES: Cannot flush signals SIGKILL, SIGCONT, SIGSTOP.
; Blocked signals are flushed too.
; -----------------------------------------------------------------------------
; ------------- Push registers
SignalFlushAllU:push eax ; push EAX
push edx ; push EDX
; ------------- Flush signals
xor eax,eax ; EAX <- 0
dec eax ; EAX <- -1
mov edx,eax ; EDX <- -1
call SignalFlushU ; flush signals from user
; ------------- Pop registers
pop edx ; pop EDX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Flush all pending signals (from kernel)
; -----------------------------------------------------------------------------
; NOTES: Blocked signals are flushed too.
; -----------------------------------------------------------------------------
; ------------- Push registers
SignalFlushAll: push eax ; push EAX
push edx ; push EDX
; ------------- Flush signals
xor eax,eax ; EAX <- 0
dec eax ; EAX <- -1
mov edx,eax ; EDX <- -1
call SignalFlush ; flush signals
; ------------- Pop registers
pop edx ; pop EDX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Get signal action
; -----------------------------------------------------------------------------
; INPUT: AL = signal number (0 to 63)
; OUTPUT: ECX = signal action flags
; EDX = signal handler
; EDI:ESI = signal action mask (1=signal is enabled)
; -----------------------------------------------------------------------------
; ------------- Push registers
SignalGetAction:push eax ; push EAX
push ebx ; push EBX
pushf ; push flags
cli ; disable interrupts
; ------------- Prepare default handler
mov ecx,SA_RESET ; default flags
xor edx,edx ; EDX <- 0, default handler
xor esi,esi ; ESI <- 0
dec esi ; ESI <- -1, signals enabled
mov edi,esi ; EDI <- -1, signals enabled
; ------------- Check if signal number is valid
cmp al,63 ; maximal signal number
ja SignalGetAct8 ; invalid signal number
cmp al,SIGNULL ; signal SIGNULL?
je SignalGetAct8 ; signal SIGNULL is always ignored
; ------------- Prepare pointer to signal action table (-> EBX)
CURRENT ebx ; EBX <- get current task
mov ebx,[ebx+TASK_SigAction] ; EBX <- action table
; ------------- Lock signal action table
%ifdef SMP
LOCK_Lock ebx ; lock signal action table
%endif
; ------------- Prepare pointer to signal action (-> EAX)
movzx eax,al ; EAX <- signal number
shl eax,4 ; EAX <- offset in signal action table
add eax,ebx ; EAX <- pointer into table
; ------------- Get signal action
mov edx,[eax+SA_Handler] ; get signal handler
mov ecx,[eax+SA_Flags] ; get flags
mov esi,[eax+SA_Mask] ; get signal mask LOW
mov edi,[eax+SA_Mask+4] ; get signal mask HIGH
; ------------- Unlock signal action table
%ifdef SMP
LOCK_Unlock ebx ; unlock signal action table
%endif
; ------------- Pop registers
SignalGetAct8: popf ; pop flags
pop ebx ; pop EBX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Make signal action table private (duplicate it if it is shared)
; -----------------------------------------------------------------------------
; OUTPUT: CY = error (not enough memory to create new table)
; LOCKS: SysMemLock
; NOTES: Action table must be in locked state with interrupts disabled.
; -----------------------------------------------------------------------------
; ------------- Push registers
SignalUnshare: pusha ; push all registers
; ------------- Get current task (-> EDX)
CURRENT edx ; EDX <- get current task
; ------------- Get signal actiom table (-> EBX)
mov ebx,[edx+TASK_SigAction] ; EBX <- action table
; ------------- Check if table requires copy-on-write
cmp dword [ebx+ST_Ref],byte 1 ; is this table private?
je SignalUnshare8 ; table is already private
; ------------- Create new signal action table
mov eax,SIGTAB_size ; EAX <- size of signal action table
call SysMemAlloc ; get new signal action table
jc SignalUnshare8 ; memory error
; ------------- Copy signal action table contents
mov esi,ebx ; ESI <- old table
mov edi,eax ; EDI <- new table
mov ecx,SIGTAB_size/4 ; ECX <- signal table size / 4
rep movsd ; copy signal action table
; ------------- Set new reference counter
inc ecx ; ECX <- 1
mov [eax+ST_Ref],ecx ; initialize reference counter (=1)
; ------------- Release old reference counter
dec dword [ebx+ST_Ref] ; decrease old reference counter
; ------------- Store pointer to new signal action table
mov [edx+TASK_SigAction],eax ; store new action table
; ------------- Unlock old signal action table
%ifdef SMP
LOCK_Unlock ebx ; unlock old signal action table
%endif
clc ; clear error flag
; ------------- Pop registers
SignalUnshare8: popa ; pop all registers
SignalUnshare9: ret
; -----------------------------------------------------------------------------
; Set signal action
; -----------------------------------------------------------------------------
; INPUT: AL = signal number (0 to 63)
; ECX = new signal action flags
; EDX = new signal handler (or SA_DEF, SA_IGN, ...)
; EDI:ESI = new signal action mask (1=signal is enabled)
; OUTPUT: CY = error (not enough memory to copy-on-write action table)
; ECX = old signal action flags
; EDX = old signal handler
; EDI:ESI = old signal action mask (1=signal is enabled)
; LOCKS: TASK_SigLock
; NOTES: SIGNULL, SIGKILL, SIGCONT, SIGSTOP have always default action.
; SIGKILL, SIGCONT and SIGSTOP are always enabled.
; -----------------------------------------------------------------------------
; ------------- Check if signal number is valid (return NC)
SignalSetAction:cmp al,63 ; maximal signal number
ja short SignalUnshare9 ; invalid signal number
; ------------- Signals with default handler (returns NC)
cmp al,SIGNULL ; signal SIGNULL?
je short SignalUnshare9 ; ignore signal SIGNULL
cmp al,SIGKILL ; signal SIGKILL?
je short SignalUnshare9 ; signal has default handler
cmp al,SIGCONT ; signal SIGCONT?
je short SignalUnshare9 ; signal has default handler
cmp al,SIGSTOP ; signal SIGSTOP?
je short SignalUnshare9 ; signal has default handler
; ------------- Push registers
push eax ; push EAX
push ebx ; push EBX
pushf ; push flags
cli ; disable interrupts
; ------------- Enable signals SIGKILL, SIGCONT, SIGSTOP
or esi,(1<<SIGKILL)+(1<<SIGCONT)+(1<<SIGSTOP)
; ------------- Prepare pointer to signal action table (-> EBX)
CURRENT ebx ; EBX <- get current task
mov ebx,[ebx+TASK_SigAction] ; EBX <- action table
; ------------- Lock signal action table
%ifdef SMP
LOCK_Lock ebx ; lock signal action table
%endif
; ------------- Prepare pointer to signal action (-> EAX)
movzx eax,al ; EAX <- signal number
shl eax,4 ; EAX <- offset in signal action table
add eax,ebx ; EAX <- pointer into table
; ------------- Check if table is private
cmp dword [ebx+ST_Ref],byte 1 ; is this table private?
je SignalSetAct6 ; talbe is already private
; ------------- Check if change signal action entries
cmp edx,[eax+SA_Handler] ; set/get new signal handler
jne SignalSetAct2 ; change
cmp ecx,[eax+SA_Flags] ; set/get new flags
jne SignalSetAct2 ; change
cmp esi,[eax+SA_Mask] ; set/get signal mask LOW
jne SignalSetAct2 ; change
cmp edi,[eax+SA_Mask+4] ; set/get signal mask HIGH
je SignalSetAct8 ; no change
; ------------- Duplicate signal action table if it is shares
SignalSetAct2: sub eax,ebx ; EAX <- offset in action table
call SignalUnshare ; unshare signal action table
jnc SignalSetAct4 ; memory is OK
; ------------- Memory error
%ifdef SMP
LOCK_Unlock ebx ; unlock signal action table
%endif
popf ; pop flags
stc ; set error flag
pop ebx ; pop EBX
pop eax ; pop EAX
ret
; ------------- Get new signal action (after unsharing)
SignalSetAct4: CURRENT ebx ; EBX <- get current task
mov ebx,[ebx+TASK_SigAction] ; EBX <- action table
add eax,ebx ; EAX <- new signal action
; ------------- Set new signal action
SignalSetAct6: xchg edx,[eax+SA_Handler] ; set/get new signal handler
xchg ecx,[eax+SA_Flags] ; set/get new flags
xchg esi,[eax+SA_Mask] ; set/get signal mask LOW
xchg edi,[eax+SA_Mask+4] ; set/get signal mask HIGH
; ------------- Unlock signal action table
SignalSetAct8:
%ifdef SMP
LOCK_Unlock ebx ; unlock signal action table
%endif
; ------------- Pop registers
SignalSetAct9: popf ; pop flags
clc ; clear error flag
pop ebx ; pop EBX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Get signal mask
; -----------------------------------------------------------------------------
; OUTPUT: EDX:EAX = signal mask (1=signal is enabled)
; -----------------------------------------------------------------------------
; ------------- Push registers
SignalGetMask: push ebx ; push EBX
; ------------- Get current task (-> EBX)
CURRENT ebx ; EBX <- get current task
; ------------- Get signal mask
mov eax,[ebx+TASK_SigMask] ; get signal mask LOW
mov edx,[ebx+TASK_SigMask+4] ; get signal mask HIGH
; ------------- Pop registers
pop ebx ; pop EBX
ret
; -----------------------------------------------------------------------------
; Set signal mask (from user, cannot disable SIGKILL, SIGCONT, SIGSTOP)
; -----------------------------------------------------------------------------
; INPUT: EDX:EAX = new signal mask (1=signal is enabled)
; OUTPUT: EDX:EAX = old signal mask (1=signal is enabled)
; -----------------------------------------------------------------------------
; ------------- Enable signals SIGKILL, SIGCONT, SIGSTOP
SignalSetMaskU: or eax,(1<<SIGKILL)+(1<<SIGCONT)+(1<<SIGSTOP)
; SignalSetMask must follow!
; -----------------------------------------------------------------------------
; Set signal mask (from kernel)
; -----------------------------------------------------------------------------
; INPUT: EDX:EAX = new signal mask (1=signal is enabled)
; OUTPUT: EDX:EAX = old signal mask (1=signal is enabled)
; -----------------------------------------------------------------------------
; ------------- Push registers
SignalSetMask: push ebx ; push EBX
; ------------- Get current task (-> EBX)
CURRENT ebx ; EBX <- get current task
; ------------- Set/get new signal mask
xchg eax,[ebx+TASK_SigMask] ; set/get signal mask LOW
xchg edx,[ebx+TASK_SigMask+4] ; set/get signal mask HIGH
; ------------- Reschedule task
mov ebx,[ebx+TASK_RunQueue] ; EBX <- current run-queue
RESCHEDULE ebx ; reschedule request
; ------------- Pop registers
pop ebx ; pop EBX
ret
; -----------------------------------------------------------------------------
; Enable one signal
; -----------------------------------------------------------------------------
; INPUT: AL = signal number (0 to 63)
; -----------------------------------------------------------------------------
; ------------- Check signal number
SignalEnable: cmp al,63 ; maximal signal number
ja SignalEnable8 ; invalid signal number
; ------------- Push registers
push eax ; push EAX
push ebx ; push EBX
; ------------- Get current task (-> EBX)
CURRENT ebx ; EBX <- get current task
; ------------- Set signal mask
movzx eax,al ; EAX <- signal number
%ifdef SMP
lock ; CPU instruction lock
%endif
bts [ebx+TASK_SigMask],eax ; set signal mask
jc SignalEnable4 ; signal was already enabled
; ------------- Reschedule task
mov ebx,[ebx+TASK_RunQueue] ; EBX <- current run-queue
RESCHEDULE ebx ; reschedule request
; ------------- Pop registers
SignalEnable4: pop ebx ; pop EBX
pop eax ; pop EAX
SignalEnable8: ret
; -----------------------------------------------------------------------------
; Disable one signal (from user, cannot disable SIGKILL, SIGCONT, SIGSTOP)
; -----------------------------------------------------------------------------
; INPUT: AL = signal number (0 to 63, except SIGKILL, SIGCONT, SIGSTOP)
; -----------------------------------------------------------------------------
; ------------- Check signal number
SignalDisableU: cmp al,SIGKILL ; is it KILL signal?
je SignalDisable8 ; cannot be disabled
cmp al,SIGCONT ; is it CONTINUE signal?
je SignalDisable8 ; cannot be disabled
cmp al,SIGSTOP ; is it STOP signal?
je SignalDisable8 ; cannot be disabled
; SignalDisable must follow!
; -----------------------------------------------------------------------------
; Disable one signal (from kernel)
; -----------------------------------------------------------------------------
; INPUT: AL = signal number (0 to 63)
; -----------------------------------------------------------------------------
; ------------- Check signal number
SignalDisable: cmp al,63 ; maximal signal number
ja SignalDisable8 ; invalid signal number
; ------------- Push registers
push eax ; push EAX
push ebx ; push EBX
; ------------- Get current task (-> EBX)
CURRENT ebx ; EBX <- get current task
; ------------- Clear signal mask
movzx eax,al ; EAX <- signal number
%ifdef SMP
lock ; CPU instruction lock
%endif
btr [ebx+TASK_SigMask],eax ; clear signal mask
; ------------- Pop registers
pop ebx ; pop EBX
pop eax ; pop EAX
SignalDisable8: ret
; -----------------------------------------------------------------------------
; Check if signal is enabled
; -----------------------------------------------------------------------------
; INPUT: AL = signal number (0 to 63)
; OUTPUT: CY = signal is disabled
; -----------------------------------------------------------------------------
; ------------- Check signal number
SignalEnabled: cmp al,63 ; maximal signal number
ja SignalEnabled8 ; invalid signal number (=NC)
; ------------- Push registers
push eax ; push EAX
push ebx ; push EBX
; ------------- Get current task (-> EBX)
CURRENT ebx ; EBX <- get current task
; ------------- Test signal mask
movzx eax,al ; EAX <- signal number
bt [ebx+TASK_SigMask],eax ; test signal mask (CY=enabled)
; ------------- Pop registers
pop ebx ; pop EBX
pop eax ; pop EAX
SignalEnabled8: cmc ; invert flag
ret
; -----------------------------------------------------------------------------
; Data
; -----------------------------------------------------------------------------
DATA_SECTION
align 4, db 0
; ------------- Signal default actions
SignalDefAct: db SA_IGN ; 0: SIGNULL, unused signal
db SA_TERM ; 1: SIGHUP, hang up terminal
db SA_TERM ; 2: SIGINT, interrupt from keyboard
db SA_DUMP ; 3: SIGQUIT, quit from keyboard
db SA_DUMP ; 4: SIGILL, illegal instruction
db SA_DUMP ; 5: SIGTRAP, trace/breakpoint trap
db SA_DUMP ; 6: SIGABRT, abort
db SA_DUMP ; 7: SIGBUS, bus error
db SA_DUMP ; 8: SIGFPE, floating-point exception
db SA_TERM ; 9: SIGKILL, kill, termination
db SA_TERM ; 10: SIGUSR1, user defined signal 1
db SA_DUMP ; 11: SIGSEGV, invalid memory reference
db SA_TERM ; 12: SIGUSR2, user defined signal 2
db SA_TERM ; 13: SIGPIPE, write without readers
db SA_TERM ; 14: SIGALRM, real timer expired
db SA_TERM ; 15: SIGTERM, process termination
db SA_TERM ; 16: SIGSTKFLT, FPU stack error
db SA_IGN ; 17: SIGCHLD, child state changed
db SA_IGN ; 18: SIGCONT, resume execution
db SA_STOP ; 19: SIGSTOP, pause process execution
db SA_STOP ; 20: SIGTSTP, suspend request from tty
db SA_STOP ; 21: SIGTTIN, tty input for background
db SA_STOP ; 22: SIGTTOU, tty output for background
db SA_IGN ; 23: SIGURG, urgent condition on socket
db SA_DUMP ; 24: SIGXCPU, CPU time limit exceeded
db SA_DUMP ; 25: SIGXFSZ, file size limit exceeded
db SA_TERM ; 26: SIGVTALRM, virtual timer expired
db SA_TERM ; 27: SIGPROF, profiling timer expired
db SA_IGN ; 28: SIGWINCH, window resizing
db SA_TERM ; 29: SIGIO, input/output now possible
db SA_TERM ; 30: SIGPWR, power supply failure
db SA_DUMP ; 31: SIGSYS, bad system call
|