about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2014-11-06 16:08:16 -0800
committerKartik K. Agaram <vc@akkartik.com>2014-11-06 16:08:16 -0800
commit40544ff87cf82d84c051659c971093ffb534b0d6 (patch)
treed4497a34975a3277295aae7800b7abfe5019e140
parent64579cf7c812e4ffe659fc6f1b1614bfc5848f22 (diff)
downloadmu-40544ff87cf82d84c051659c971093ffb534b0d6.tar.gz
238 - avoid deadlock if all jobs are sleeping
-rw-r--r--mu.arc11
-rw-r--r--mu.arc.t24
2 files changed, 33 insertions, 2 deletions
diff --git a/mu.arc b/mu.arc
index 5779ac47..0aed2f73 100644
--- a/mu.arc
+++ b/mu.arc
@@ -190,7 +190,9 @@
   (each it fn-names
     (enq make-routine.it running-routines*))
   ; simple round-robin scheduler
-  (while (~empty running-routines*)
+  (while (or (~empty running-routines*)
+             (~empty sleeping-routines*))
+    (point continue
     (each (routine _) sleeping-routines*
       (awhen (> curr-cycle* rep.routine!sleep.1)
         (trace "schedule" "waking up " top.routine!fn-name)
@@ -198,6 +200,11 @@
         (wipe rep.routine!sleep)
         (++ pc.routine)  ; complete the sleep instruction
         (enq routine running-routines*)))
+    (when (empty running-routines*)
+      ; ensure forward progress
+      (trace "schedule" "skipping cycle " curr-cycle*)
+      (++ curr-cycle*)
+      (continue))
     (= routine* deq.running-routines*)
     (trace "schedule" top.routine*!fn-name)
     (routine-mark:run-for-time-slice scheduling-interval*)
@@ -207,7 +214,7 @@
         (~empty routine*)
           (enq routine* running-routines*)
         :else
-          (enq-limit routine* completed-routines*))))
+          (enq-limit routine* completed-routines*)))))
 
 (def die (msg)
   (= rep.routine*!error msg)
diff --git a/mu.arc.t b/mu.arc.t
index 41561520..4050a6aa 100644
--- a/mu.arc.t
+++ b/mu.arc.t
@@ -1698,6 +1698,30 @@
     ("run" "f1 2")
   ))
 
+(reset)
+(new-trace "sleep-long")
+(add-fns
+  '((f1
+      (sleep (20 literal))
+      ((1 integer) <- copy (3 literal))
+      ((1 integer) <- copy (3 literal)))
+    (f2
+      ((2 integer) <- copy (4 literal))
+      ((2 integer) <- copy (4 literal)))))
+;? (= dump-trace* (obj whitelist '("run" "schedule")))
+(= scheduling-interval* 1)
+(run 'f1 'f2)
+(check-trace-contents "scheduler progresses sleeping routines when there are no routines left to run"
+  '(("run" "f1 0")
+    ("run" "sleeping until 21")
+    ("schedule" "pushing f1 to sleep queue")
+    ("run" "f2 0")
+    ("run" "f2 1")
+    ("schedule" "waking up f1")
+    ("run" "f1 1")
+    ("run" "f1 2")
+  ))
+
 ; The scheduler needs to keep track of the call stack for each routine.
 ; Eventually we'll want to save this information in mu's address space itself,
 ; along with the types array, the magic buffers for args and oargs, and so on.