@@ -20,7 +20,7 @@ type Word = arch.Word
2020func (m * InstrumentedState ) handleSyscall () error {
2121 thread := m .state .GetCurrentThread ()
2222
23- syscallNum , a0 , a1 , a2 , a3 := exec .GetSyscallArgs (m .state .GetRegistersRef ())
23+ syscallNum , a0 , a1 , a2 := exec .GetSyscallArgs (m .state .GetRegistersRef ())
2424 v0 := Word (0 )
2525 v1 := Word (0 )
2626
@@ -43,12 +43,9 @@ func (m *InstrumentedState) handleSyscall() error {
4343 v0 = m .state .NextThreadId
4444 v1 = 0
4545 newThread := & ThreadState {
46- ThreadId : m .state .NextThreadId ,
47- ExitCode : 0 ,
48- Exited : false ,
49- FutexAddr : exec .FutexEmptyAddr ,
50- FutexVal : 0 ,
51- FutexTimeoutStep : 0 ,
46+ ThreadId : m .state .NextThreadId ,
47+ ExitCode : 0 ,
48+ Exited : false ,
5249 Cpu : mipsevm.CpuScalars {
5350 PC : thread .Cpu .NextPC ,
5451 NextPC : thread .Cpu .NextPC + 4 ,
@@ -119,37 +116,18 @@ func (m *InstrumentedState) handleSyscall() error {
119116 v0 = exec .SysErrorSignal
120117 v1 = exec .MipsEAGAIN
121118 } else {
122- thread .FutexAddr = effFutexAddr
123- thread .FutexVal = targetVal
124- if a3 == 0 {
125- thread .FutexTimeoutStep = exec .FutexNoTimeout
126- } else {
127- thread .FutexTimeoutStep = m .state .Step + exec .FutexTimeoutSteps
128- }
129- // Leave cpu scalars as-is. This instruction will be completed by `onWaitComplete`
119+ m .syscallYield (thread )
130120 return nil
131121 }
132122 case exec .FutexWakePrivate :
133- // Trigger a wakeup traversal
134- m .state .Wakeup = effFutexAddr
135- // Don't indicate to the program that we've woken up a waiting thread, as there are no guarantees.
136- // The woken up thread should indicate this in userspace.
137- v0 = 0
138- v1 = 0
139- exec .HandleSyscallUpdates (& thread .Cpu , & thread .Registers , v0 , v1 )
140- m .preemptThread (thread )
141- m .state .TraverseRight = len (m .state .LeftThreadStack ) == 0
142- m .statsTracker .trackWakeupTraversalStart ()
123+ m .syscallYield (thread )
143124 return nil
144125 default :
145126 v0 = exec .SysErrorSignal
146127 v1 = exec .MipsEINVAL
147128 }
148129 case arch .SysSchedYield , arch .SysNanosleep :
149- v0 = 0
150- v1 = 0
151- exec .HandleSyscallUpdates (& thread .Cpu , & thread .Registers , v0 , v1 )
152- m .preemptThread (thread )
130+ m .syscallYield (thread )
153131 return nil
154132 case arch .SysOpen :
155133 v0 = exec .SysErrorSignal
@@ -225,6 +203,13 @@ func (m *InstrumentedState) handleSyscall() error {
225203 return nil
226204}
227205
206+ func (m * InstrumentedState ) syscallYield (thread * ThreadState ) {
207+ v0 := Word (0 )
208+ v1 := Word (0 )
209+ exec .HandleSyscallUpdates (& thread .Cpu , & thread .Registers , v0 , v1 )
210+ m .preemptThread (thread )
211+ }
212+
228213func (m * InstrumentedState ) mipsStep () error {
229214 err := m .doMipsStep ()
230215 if err != nil {
@@ -249,56 +234,12 @@ func (m *InstrumentedState) doMipsStep() error {
249234 m .state .Step += 1
250235 thread := m .state .GetCurrentThread ()
251236
252- // During wakeup traversal, search for the first thread blocked on the wakeup address.
253- // Don't allow regular execution until we have found such a thread or else we have visited all threads.
254- if m .state .Wakeup != exec .FutexEmptyAddr {
255- // We are currently performing a wakeup traversal
256- if m .state .Wakeup == thread .FutexAddr {
257- // We found a target thread, resume normal execution and process this thread
258- m .state .Wakeup = exec .FutexEmptyAddr
259- } else {
260- // This is not the thread we're looking for, move on
261- traversingRight := m .state .TraverseRight
262- changedDirections := m .preemptThread (thread )
263- if traversingRight && changedDirections {
264- // We started the wakeup traversal walking left and we've now walked all the way right
265- // We have therefore visited all threads and can resume normal thread execution
266- m .state .Wakeup = exec .FutexEmptyAddr
267- }
268- }
269- return nil
270- }
271-
272237 if thread .Exited {
273238 m .popThread ()
274239 m .stackTracker .DropThread (thread .ThreadId )
275240 return nil
276241 }
277242
278- // check if thread is blocked on a futex
279- if thread .FutexAddr != exec .FutexEmptyAddr {
280- // if set, then check futex
281- // check timeout first
282- if m .state .Step > thread .FutexTimeoutStep {
283- // timeout! Allow execution
284- m .onWaitComplete (thread , true )
285- return nil
286- } else {
287- futexVal := m .getFutexValue (thread .FutexAddr )
288- if thread .FutexVal == futexVal {
289- // still got expected value, continue sleeping, try next thread.
290- m .preemptThread (thread )
291- m .statsTracker .trackWakeupFail ()
292- return nil
293- } else {
294- // wake thread up, the value at its address changed!
295- // Userspace can turn thread back to sleep if it was too sporadic.
296- m .onWaitComplete (thread , false )
297- return nil
298- }
299- }
300- }
301-
302243 if m .state .StepsSinceLastContextSwitch >= exec .SchedQuantum {
303244 // Force a context switch as this thread has been active too long
304245 if m .state .ThreadCount () > 1 {
@@ -412,24 +353,6 @@ func (m *InstrumentedState) handleRMWOps(insn, opcode uint32) error {
412353 return exec .HandleRd (m .state .getCpuRef (), m .state .GetRegistersRef (), rtReg , retVal , true )
413354}
414355
415- func (m * InstrumentedState ) onWaitComplete (thread * ThreadState , isTimedOut bool ) {
416- // Note: no need to reset m.state.Wakeup. If we're here, the Wakeup field has already been reset
417- // Clear the futex state
418- thread .FutexAddr = exec .FutexEmptyAddr
419- thread .FutexVal = 0
420- thread .FutexTimeoutStep = 0
421-
422- // Complete the FUTEX_WAIT syscall
423- v0 := Word (0 )
424- v1 := Word (0 )
425- if isTimedOut {
426- v0 = exec .SysErrorSignal
427- v1 = exec .MipsETIMEDOUT
428- }
429- exec .HandleSyscallUpdates (& thread .Cpu , & thread .Registers , v0 , v1 )
430- m .statsTracker .trackWakeup ()
431- }
432-
433356func (m * InstrumentedState ) preemptThread (thread * ThreadState ) bool {
434357 // Pop thread from the current stack and push to the other stack
435358 if m .state .TraverseRight {
0 commit comments