unit kern_synch; {$mode ObjFPC}{$H+} {$CALLING SysV_ABI_CDecl} interface uses sys_sleepqueue, kern_param, kern_mtx, kern_thr; function msleep(ident :Pointer; lock :p_mtx; priority:Integer; wmesg :PChar; timo :Int64):Integer; function tsleep(ident :Pointer; priority:Integer; wmesg :PChar; timo :Int64):Integer; function pause(wmesg:PChar;timo:Int64):Integer; procedure wakeup(ident:Pointer); procedure wakeup_one(ident:Pointer); function mi_switch(flags:Integer):Integer; procedure maybe_yield(); procedure kern_yield(prio:Integer); function sys_yield():Integer; function sys_sched_yield():Integer; function sys_cpumode_yield():Integer; implementation uses kern_proc, sched_ule, md_sleep, rtprio; var pause_wchan:Integer=0; function msleep(ident :Pointer; lock :p_mtx; priority:Integer; wmesg :PChar; timo :Int64):Integer; public; var td:p_kthread; catch,flags,pri:Integer; begin td:=curkthread; catch:=priority and PCATCH; pri :=priority and PRIMASK; if (TD_ON_SLEEPQ(td)) then begin sleepq_remove(td,td^.td_wchan); end; if (ident=@pause_wchan) then flags:=SLEEPQ_PAUSE else flags:=SLEEPQ_SLEEP; if (catch<>0) then begin flags:=flags or SLEEPQ_INTERRUPTIBLE; end; if ((priority and PBDRY)<>0) then begin flags:=flags or SLEEPQ_STOP_ON_BDRY; end; sleepq_lock(ident); if (lock<>nil) then //not LC_SLEEPABLE begin mtx_unlock(lock^); end; { * We put ourselves on the sleep queue and start our timeout * before calling thread_suspend_check, as we could stop there, * and a wakeup or a SIGCONT (or both) could occur while we were * stopped without resuming us. Thus, we must be ready for sleep * when cursig() is called. If the wakeup happens while we're * stopped, then td will no longer be on a sleep queue upon * return from cursig(). } sleepq_add(ident,lock,wmesg,flags,0); sleepq_set_timeout(ident,timo); if (timo<>0) and (catch<>0) then Result:=sleepq_timedwait_sig(ident,pri) else if (timo<>0) then Result:=sleepq_timedwait(ident,pri) else if (catch<>0) then Result:=sleepq_wait_sig(ident,pri) else begin sleepq_wait(ident,pri); Result:=0; end; //sleepq_release in sleepq_switch if (lock<>nil) and ((priority and PDROP)=0) then begin mtx_lock(lock^); end; end; function tsleep(ident :Pointer; priority:Integer; wmesg :PChar; timo :Int64):Integer; public; begin Result:=msleep(ident,nil,priority,wmesg,timo); end; function pause(wmesg:PChar;timo:Int64):Integer; public; begin // silently convert invalid timeouts if (timo < 1) then timo:=1; Result:=(tsleep(@pause_wchan, 0, wmesg, timo)); end; procedure wakeup(ident:Pointer); public; begin sleepq_lock(ident); sleepq_broadcast(ident,SLEEPQ_SLEEP,0,0); sleepq_release(ident); end; procedure wakeup_one(ident:Pointer); public; begin sleepq_lock(ident); sleepq_signal(ident,SLEEPQ_SLEEP,0,0); sleepq_release(ident); end; function mi_switch(flags:Integer):Integer; public; var td:p_kthread; begin Result:=0; td:=curkthread; thread_lock_assert(td); if (td<>nil) then begin if (flags and SW_VOL)<>0 then begin System.InterlockedIncrement64(td^.td_ru.ru_nvcsw); System.InterlockedIncrement64(p_proc.p_nvcsw); end else begin System.InterlockedIncrement64(td^.td_ru.ru_nivcsw); System.InterlockedIncrement64(p_proc.p_nivcsw); end; end; case (flags and SW_TYPE_MASK) of SWT_RELINQUISH, SWT_NEEDRESCHED: begin if (td<>nil) then begin thread_unlock(td); end; md_yield; if (td<>nil) then begin thread_lock(td); end; end; SWT_SLEEPQ, SWT_SLEEPQTIMO: begin if (td=nil) then Exit(-1); Result:=sched_switch(td); end; SWT_SUSPEND: begin if (td=nil) then Exit(-1); td^.td_slptick:=0; //infinite Result:=sched_switch(td); end; end; end; procedure maybe_yield(); begin kern_yield(PRI_USER); end; procedure kern_yield(prio:Integer); var td:p_kthread; begin td:=curkthread; if (td<>nil) then begin thread_lock(td); if (prio=PRI_USER) then begin prio:=td^.td_user_pri; end; if (prio>=0) then begin sched_prio(td, prio); end; end; mi_switch(SW_VOL or SWT_RELINQUISH); if (td<>nil) then begin thread_unlock(td); end; end; function sys_yield():Integer; var td:p_kthread; begin td:=curkthread; if (td<>nil) then begin thread_lock(td); if (PRI_BASE(td^.td_pri_class)=PRI_TIMESHARE) then begin sched_prio(td, PRI_MAX_TIMESHARE); end; td^.td_retval[0]:=0; end; mi_switch(SW_VOL or SWT_RELINQUISH); if (td<>nil) then begin thread_unlock(td); end; Exit(0); end; function sys_sched_yield():Integer; begin Result:=sys_yield; end; function sys_cpumode_yield():Integer; begin Result:=sys_yield; end; end.