You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Spyxorigthread; // thread number that is working on this pyx, or _1 if the value is available
183
183
Cerrcode; // 0 if no error, or error code
184
184
#ifPYXES
185
-
UI4state;//one of the below pyx states. Monotonically increases
185
+
UI4state;//one of the below pyx states
186
186
#endif
187
187
} PYXBLOK;
188
188
enum{ // pyx state is low 2 bytes of state. High 2 bytes are the wakeup sequence number
189
189
PYXEMPTY=0, //the pyx is not filled in, and no one is waiting
190
-
PYXWAIT=3, //at least 1 thread is waiting, and the pyx is not filled in
191
-
PYXFULL=1}; //the pyx is filled in. We can OR FULL into pyx state to move to FULL state
190
+
PYXWAIT=3, //at least 1 thread is waiting, and the pyx is not filled in. We can OR WAIT into pyx state to move to WAIT state
191
+
PYXFULL=1}; //the pyx is filled in
192
192
#ifPYXES
193
193
194
194
// Install a value/errcode into a (recursive) pyx, and broadcast to anyone waiting on it. fa() the pyx to indicate that the thread has released the pyx
@@ -221,15 +221,15 @@ static A jtcreatepyx(J jt, I thread,D timeout){A pyx;
if(PYXFULL==(state=lda((US*)&blok->state)))goto done; // if pyx already full, return result
224
-
casa((US*)&blok->state,&(US){PYXEMPTY},PYXWAIT); // if pyx is EMPTY, move it to WAIT
224
+
{USdummy=0;casa(state!=PYXEMPTY?&dummy:(US*)&blok->state,&(US){PYXEMPTY},PYXWAIT);}// if pyx is EMPTY, move it to WAIT. Avoid excess contention on hot pyxes
225
225
UIns=({Dmwt=blok->pyxmaxwt;mwt==inf?IMAX:(I)(mwt*1e9);}); // figure out how long to wait
226
226
structjtimespecend=jtmtil(ns); // get the time when we have to give up on this pyx
227
227
Ierr;
228
-
sta(&jt->futexwt,&blok->state); // make sure systemlock knows how to wake us up. We check for system events AFTER this store, but before the wait (but wakeall has a window so it is called repeatedly anyway)
228
+
sta(&jt->futexwt,&blok->state); // make sure systemlock knows how to wake us up. We check for system events AFTER this store, but before the wait
229
229
while(1){ // repeat till state goes to FULL
230
-
if(lda((US*)&blok->state)==PYXFULL)break; // if pyx was filled, exit and return its value
231
230
// The wait may time out because of a pending system action (BREAK or system lock). If so, we accept it now...
232
231
UI4state=lda(&blok->state); Cbreakb; // get store sequence # before we check for system event
232
+
if(PYXFULL==(state&0xffff))break; // if pyx was filled, exit and return its value
233
233
if(unlikely(BETWEENC(lda(&JT(jt,systemlock)),1,2))){jtsystemlockaccept(jt,LOCKALL);} // process systemlock and keep waiting
234
234
// the user may be requesting a BREAK interrupt for deadlock or other slow execution
235
235
if(unlikely((breakb=lda(&JT(jt,adbreak)[0])))!=0){err=breakb==1?EVATTN:EVBREAK;goto fail;} // JBREAK: give up on the pyx and exit
else{err=EVTIME;goto fail;}} // otherwise, timeout, fail the pyx and exit
239
239
Iwr=jfutex_waitn(&blok->state,state|PYXWAIT,ns);if(unlikely(wr>0)){err=EVFACE;goto fail;} // wait on futex. If new event# or state has moved off of WAIT, don't wait
240
240
}
241
-
sta(&jt->futexwt,0); while(lda(&JT(jt,wakeallct)))YIELD; // wait till pending wakealls complete before we allow this block to be deleted
241
+
CLRFUTEXWT; // wait till pending wakealls complete before we allow this block to be deleted
242
242
done: // pyx has been filled in. jt->futexwt must be 0
243
243
if(likely(blok->pyxvalue!=NULL))Rblok->pyxvalue; // valid value, use it
244
244
ASSERT(0,blok->errcode); // if error, return the error code
Copy file name to clipboardExpand all lines: jsrc/mt.c
+8-7Lines changed: 8 additions & 7 deletions
Original file line number
Diff line number
Diff line change
@@ -156,7 +156,7 @@ C jtpthread_mutex_lock(J jt,jtpthread_mutex_t *m,I self){ //lock m; self is thre
156
156
//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
157
157
// Before waiting, handle system events if present
158
158
UI4waitval=lda(&m->v); Cbreakb; // 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
159
-
if(unlikely(BETWEENC(lda(&JT(jt,systemlock)),1,2))){jtsystemlockaccept(jt,LOCKALL);} // if system lock requested, accept it
159
+
if(unlikely(BETWEENC(lda(&JT(jt,systemlock)),1,2))){jtsystemlockaccept(jt,LOCKALL);continue;} // if system lock requested, accept it. Then retry; a lot can happen during a systemlock, and we probably need to resample waitval anyway
160
160
// the user may be requesting a BREAK interrupt for deadlock or other slow execution
161
161
if(unlikely((breakb=lda(&JT(jt,adbreak)[0])))!=0){r=breakb==1?EVATTN:EVBREAK;goto fail;} // JBREAK: give up on the pyx and exit
162
162
// Now wait for a change. The futex_wait is atomic, and will wait only if the state is WAIT. In that case,
@@ -170,10 +170,10 @@ C jtpthread_mutex_lock(J jt,jtpthread_mutex_t *m,I self){ //lock m; self is thre
m->ct+=m->recursive;m->owner=self;R0; // install ownership info, good return
176
-
fail:clrfutexwt(jt); Rr;} // error return, with our internal errorcode
176
+
fail:CLRFUTEXWT; Rr;} // error return, with our internal errorcode
177
177
178
178
179
179
// return positive error code, 0 if got lock, -1 if lock timed out
@@ -185,17 +185,18 @@ I jtpthread_mutex_timedlock(J jt,jtpthread_mutex_t *m,UI ns,I self){ //lock m, w
185
185
sta(&jt->futexwt,&m->v); //ensure other threads know how to wake us up for systemlock
186
186
while(xchga((US*)&m->v,WAIT)!=FREE){ //exit when _we_ successfully installed WAIT in place of FREE
187
187
UI4waitval=lda(&m->v); Cbreakb; // 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
0 commit comments