Skip to content

Commit 4265654

Browse files
committed
implement sleep in terms of futex wait when PYXES, for correct handling of systemlock and to avoid relying on signals since they don't work on windows
1 parent fde381b commit 4265654

3 files changed

Lines changed: 35 additions & 7 deletions

File tree

jsrc/mt.c

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ I jfutex_waitn(UI4 *p,UI4 v,UI ns){
123123
void jfutex_waken(UI4 *p,UI4 n){jfutex_wakea(p);} //scaf/TUNE: should DO(n,jfutex_wake1(p)) depending on n and the #threads waiting on p
124124
#endif
125125

126+
// remove wakeup to this thread; if wakeup in progress, wait till it finishes
127+
void clrfutexwt(J jt){sta(&jt->futexwt,0); while(lds(&JT(jt,wakeallct)))YIELD;}
128+
126129
//values for mutex->v. The upper 16 bits are a wait counter; the state is the low 16 bits, as follows
127130
//todo consider storing owner in the high bits of v
128131
enum{
@@ -152,7 +155,7 @@ C jtpthread_mutex_lock(J jt,jtpthread_mutex_t *m,I self){ //lock m; self is thre
152155
//ulrich drepper 'futexes are tricky' explains the issue with storing a waiter count in the value
153156
//a couple of alternatives suggest themselves: store up to k waiters (FREE/LOCK/WAIT is really 0/1/n; we could do eg 0/1/2/3/n); store the waiter count somehow outside of the value
154157
// Before waiting, handle system events if present
155-
UI4 waitval=m->v; C breakb; // get the serial number before we check
158+
UI4 waitval=lda(&m->v); C breakb; // get the serial number before we check. Must be atomic; this is supposed to synchronise with writes to the same location via futexwt by wakeall
156159
if(unlikely(BETWEENC(lda(&JT(jt,systemlock)),1,2))){jtsystemlockaccept(jt,LOCKALL);} // if system lock requested, accept it
157160
// the user may be requesting a BREAK interrupt for deadlock or other slow execution
158161
if(unlikely((breakb=lda(&JT(jt,adbreak)[0])))!=0){r=breakb==1?EVATTN:EVBREAK;goto fail;} // JBREAK: give up on the pyx and exit
@@ -167,10 +170,10 @@ C jtpthread_mutex_lock(J jt,jtpthread_mutex_t *m,I self){ //lock m; self is thre
167170
if(unlikely(i>0)){r=EVFACE; goto fail;} //handle error (unaligned unmapped interrupted...)
168171
}
169172
// come out of loop when we have the lock
170-
sta(&jt->futexwt,0); while(lda(&JT(jt,wakeallct)))YIELD; // remove wakeup to this thread; if wakeup in progress, wait till it finishes
173+
clrfutexwt(jt);
171174
}
172175
m->ct+=m->recursive;m->owner=self;R 0; // install ownership info, good return
173-
fail:sta(&jt->futexwt,0); while(lda(&JT(jt,wakeallct)))YIELD; R r;} // error return, with our internal errorcode
176+
fail:clrfutexwt(jt); R r;} // error return, with our internal errorcode
174177

175178

176179
// return positive error code, 0 if got lock, -1 if lock timed out
@@ -181,18 +184,18 @@ I jtpthread_mutex_timedlock(J jt,jtpthread_mutex_t *m,UI ns,I self){ //lock m, w
181184
struct jtimespec tgt=jtmtil(ns);
182185
sta(&jt->futexwt,&m->v); //ensure other threads know how to wake us up for systemlock
183186
while(xchga((US*)&m->v,WAIT)!=FREE){ //exit when _we_ successfully installed WAIT in place of FREE
184-
UI4 waitval=m->v; C breakb; // get the serial number before we check
187+
UI4 waitval=lda(&m->v); C breakb; // get the serial number before we check. Must be atomic; this is supposed to synchronise with writes to the same location via futexwt by wakeall
185188
if(unlikely(BETWEENC(lda(&JT(jt,systemlock)),1,2))){jtsystemlockaccept(jt,LOCKALL);}
186189
if(unlikely((breakb=lda(&JT(jt,adbreak)[0])))!=0){r=breakb==1?EVATTN:EVBREAK;goto fail;} // JBREAK: give up on the pyx and exit
187190
I i=jfutex_waitn(&m->v,waitval|WAIT,ns);
188191
if(unlikely(i>0)){r=EVFACE; goto fail;} //handle error (unaligned unmapped interrupted...)
189192
if(i==-1){r=-1;goto fail;} //if the kernel says we timed out, trust it rather than doing another syscall to check the time
190193
if(-1ull==(ns=jtmdif(tgt))){r=-1;goto fail;} //update delta, abort if timed out
191194
}
192-
sta(&jt->futexwt,0); // remove wakeup to this thread
195+
clrfutexwt(jt); // remove wakeup to this thread
193196
}
194197
m->ct+=m->recursive;m->owner=self;R 0; // install ownership info, good return
195-
fail:sta(&jt->futexwt,0);R r;} // error return, with our internal errorcode or -1 if timeout
198+
fail:clrfutexwt(jt); R r;} // error return, with our internal errorcode or -1 if timeout
196199

197200
I jtpthread_mutex_trylock(jtpthread_mutex_t *m,I self){ //attempt to acquire m
198201
if(casa((US*)&m->v,&(US){FREE},LOCK)){m->ct+=m->recursive;m->owner=self;R 0;} //fastpath: attempt to acquire the lock; if free, take it
@@ -206,4 +209,23 @@ C jtpthread_mutex_unlock(jtpthread_mutex_t *m,I self){ //release m
206209
m->owner=0; // clear owner before releasing the lock
207210
if(unlikely(xchga((US*)&m->v,FREE)==WAIT))jfutex_wake1(&m->v); // move to FREE state; if state was WAIT, wake up a waiter
208211
R 0;}
212+
213+
// misc: sleep
214+
// attempt to sleep for ns ns, with proper handling of systemlock and jbreak. Returns error code
215+
C jtjsleep(J jt,UI ns){
216+
C r=0,breakb;
217+
struct jtimespec tgt=jtmtil(ns);
218+
UI4 ftx=0;
219+
sta(&jt->futexwt,&ftx);
220+
while(1){
221+
UI4 waitval=lda(&ftx);
222+
if(unlikely(BETWEENC(lda(&JT(jt,systemlock)),1,2))){jtsystemlockaccept(jt,LOCKALL);goto retime;} //systemlock can take a long time
223+
if(unlikely((breakb=lda(&JT(jt,adbreak)[0])))!=0){r=breakb==1?EVATTN:EVBREAK;break;}
224+
I i=jfutex_waitn(&ftx,waitval|1,ns);
225+
if(unlikely(i>0)){r=EVFACE;break;}
226+
if(i==-1){r=0;break;} //timed out
227+
retime:
228+
if(-1ull==(ns=jtmdif(tgt))){r=0;break;}}
229+
clrfutexwt(jt);
230+
R r;}
209231
#endif //PYXES

jsrc/mt.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ I jtpthread_mutex_timedlock(J jt,jtpthread_mutex_t*,UI ns,I self); //absolute ti
2626
I jtpthread_mutex_trylock(jtpthread_mutex_t*,I self); //0=success -1=failure positive=error
2727
C jtpthread_mutex_unlock(jtpthread_mutex_t*,I self); //0 or error code
2828

29+
C jtjsleep(J jt,UI ns); //returns error
30+
2931
#if defined(__linux__)
3032
#include <linux/futex.h>
3133
#include <sys/syscall.h>

jsrc/xt.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,12 +264,16 @@ F1(jttsit1){R tsit2(num(1),w);}
264264
F1(jtdl){D m,n,*v;UINT ms,s;
265265
RZ(w=cvt(FL,w));
266266
n=0; v=DAV(w); DQ(AN(w), m=*v++; ASSERT(0<=m,EVDOMAIN); n+=m;);
267-
s=(UINT)jfloor(n); ms=(UINT)jround(1000*(n-s));
267+
#if PYXES
268+
C sr=jtjsleep(jt,(UI)jfloor(n*1e9));ASSERT(!sr,sr);
269+
#else
270+
s=(I)jfloor(n); ms=(I)jround(1000*(n-s));
268271
#if SYS & SYS_MACINTOSH
269272
{I t=TickCount()+(I)(60*n); while(t>TickCount())JBREAK0;}
270273
#else
271274
DQ(s, sleepms(1000); JBREAK0;);
272275
sleepms(ms);
276+
#endif
273277
#endif
274278
R w;
275279
}

0 commit comments

Comments
 (0)