shithub: mc

Download patch

ref: bd900a61b081a832b4a9f105f030a0751e9bbce5
parent: 2907edc929cb7681744567214296ecc3c48699ce
author: Ori Bernstein <[email protected]>
date: Tue Dec 17 11:18:07 EST 2013

Clean up run queue abstraction

    We were using a single array that we were shuffling, which made
    it very difficult to reason about skipped threads, doubly run
    threads, dead threads, and so on.

    Moving to a linked list run queue with tasks that run until they
    expire should simplify this.

--- a/interp.myr
+++ b/interp.myr
@@ -16,7 +16,6 @@
 	re.strp = 0
 	run(re)
 	match re.matched
-	|`std.None: -> false
 	| `std.Some thr:
 		for i = 0; i < re.nmatch; i++
 			std.put("match %z:", i)
@@ -23,25 +22,52 @@
 			std.put("[%z..%z]\n", thr.mstart[i], thr.mend[i])
 		;;
 		-> thr.mend[0] == str.len
+	| `std.None:
+		-> false
 	;;
 }
 
+const Zthr = 0 castto(rethread#)
+
 const run = {re
-	var i
+	var i, consumed
+	var thr
 
 	re.matched = `std.None
-	mkthread(re, 0)
-	re.thr[0].mstart = std.slalloc(re.nmatch)
-	re.thr[0].mend = std.slalloc(re.nmatch)
+	re.runq = mkthread(re, 0)
+	re.runq.mstart = std.slalloc(re.nmatch)
+	re.runq.mend = std.slalloc(re.nmatch)
 	for i = 0; i < re.nmatch; i++
-		re.thr[0].mstart[i] = -1
-		re.thr[0].mend[i] = -1
+		re.runq.mstart[i] = -1
+		re.runq.mend[i] = -1
 	;;
 	while re.nthr > 0
-		for i = 0; i < re.nthr; i++
-			trace(re, re.thr[i], "\ntid=%z, ip=%z, c=b\n", re.thr[i].uid, re.thr[i].ip, re.str[re.strp])
-			step(re, i)
+		while re.runq != Zthr
+			/* set up the next thread */
+			thr = re.runq
+			re.runq = thr.next
+
+			trace(re, thr, "\nrunning tid=%z, ip=%z, c=%c\n", thr.tid, thr.ip, re.str[re.strp] castto(char))
+			consumed = step(re, thr)
+			while !consumed
+				consumed = step(re, thr)
+			;;
+
+			if thr.dead
+				thrfree(re, thr)
+			elif !thr.matched
+				thr.next = re.expired
+				re.expired = thr
+			else
+				trace(re, thr, "Matched\n")
+				match re.matched
+				| `std.Some t:	std.put("HAVE MATCH\n")
+				| `std.None: std.put("WTFWTFWTF\n")
+				;;
+			;;
 		;;
+		re.runq = re.expired
+		re.expired = Zthr
 		if re.nthr > 0
 			re.strp++
 		;;
@@ -48,22 +74,24 @@
 	;;
 }
 
-const step = {re, tid
-	var thr
+/* 
+ Steps forward one instruction. Returns true if a byte of input was
+ consumed, false otherwise.
+*/
+const step = {re, thr
 	var str
 	var mstart
 	var mend
 
-	thr = re.thr[tid]
 	str = re.str
 	match re.prog[thr.ip]
 	/* Char matching. Consume exactly one byte from the string. */
 	| `Ibyte b:
-		trace(re, thr, "\t%z:\tByte %b\n", thr.ip, b)
+		trace(re, thr, "\t%z:\tByte %b (%c)\n", thr.ip, b, b castto(char))
 		if !in(re, str)
-			kill(re, tid, "end of string")
+			die(re, thr, "end of string")
 		elif b != str[re.strp]
-			kill(re, tid, "not right char")
+			die(re, thr, "not right char")
 		else
 			thr.ip++
 			trace(re, thr, "\t\tmatched %b with %b\n", b, str[re.strp])
@@ -71,7 +99,7 @@
 	| `Irange (start, end):
 		trace(re, thr, "\t%z:\tRange (%b, %b)\n", thr.ip, start, end)
 		if !in(re, str) || start > str[re.strp] || end < str[re.strp]
-			kill(re, tid, "bad range")
+			die(re, thr, "bad range")
 		else
 			thr.ip++
 		;;
@@ -83,16 +111,16 @@
 		trace(re, thr, "\t%z:\tBol\n", thr.ip)
 		if re.strp == 0 || str[re.strp - 1] == '\n' castto(byte)
 			thr.ip++
-			step(re, tid)
+			-> false
 		else
-			kill(re, tid, "not beginning of line")
+			die(re, thr, "not beginning of line")
 		;;
 	| `Ieol:
 		trace(re, thr, "\t%z:\tEol\n", thr.ip)
 		if re.strp == str.len || str[re.strp] == '\n' castto(byte)
-			step(re, tid)
+			-> false
 		else
-			kill(re, tid, "not end of line")
+			die(re, thr, "not end of line")
 		;;
 	| `Ilbra m:
 		trace(re, thr, "\t%z:\tLbra %z\n", thr.ip, m)
@@ -99,85 +127,91 @@
 		trace(re, thr, "\t\tmatch start = %z\n", re.strp)
 		thr.mstart[m] = re.strp
 		thr.ip++
-		step(re, tid)
+		-> false
 	| `Irbra m:
 		trace(re, thr, "\t%z:\tRbra %z\n", thr.ip, m)
 		thr.mend[m] = re.strp
 		thr.ip++
-		step(re, tid)
+		-> false
 	| `Ifork (lip, rip):
 		trace(re, thr, "\t%z:\tFork (%z, %z)\n", thr.ip, lip, rip)
 		mstart = std.sldup(thr.mstart)
 		mend = std.sldup(thr.mend)
-		jmp(re, tid, lip)
 		fork(re, thr, rip, mstart, mend)
+		thr.ip = lip
+		-> false
 	| `Ijmp ip:
 		trace(re, thr, "\t%z:\tJmp %z\n", thr.ip, ip)
-		jmp(re, tid, ip)
+		thr.ip = ip
+		-> false
 	| `Imatch:
 		trace(re, thr, "\t%z:\tMatch\n", thr.ip)
-		finish(re, tid)
+		finish(re, thr)
+		-> true
 	;;
+	-> true
 }
 
-const jmp = {re, tid, ip
-	re.thr[tid].ip = ip
-	step(re, tid)
+const fork = {re, thr, ip, mstart, mend
+	var thr
+
+	thr = mkthread(re, ip)
+	thr.next = re.runq
+	thr.mstart = mstart
+	thr.mend = mend
+	re.runq = thr
 }
 
-var uid = 0
+const die = {re, thr, msg
+	trace(re, thr, "\t\tdie %z: %s\n", thr.tid, msg)
+	thr.dead = true
+	re.nthr--
+}
 
+const finish = {re, thr
+	trace(re, thr, "******finish**** %z\n", tid)
+	match re.matched
+	| `std.Some t:	thrfree(re, t)
+	| `std.None:
+	;;
+	re.matched = `std.Some thr
+	thr.matched = true
+	re.nthr--
+}
+
+var tid = 0
+
 const mkthread = {re, ip
 	var thr : rethread#
-	var tid
 
-	tid = re.nthr
-	if re.nthr >= re.thr.len
-		re.thr = std.slgrow(re.thr, std.max(1, re.nthr * 2))
-	;;
-
 	thr = std.alloc()
+
+	thr.next = Zthr
+
 	thr.ip = ip
-	thr.uid = uid++
+	thr.tid = tid++
+	thr.dead = false
+	thr.matched = false
 
-	re.thr[re.nthr] = thr
+	thr.mstart = [][:]
+	thr.mend = [][:]
+
 	re.nthr++
-	-> tid
-}
 
-const fork = {re, thr, ip, mstart, mend
-	var tid
-
-	tid = mkthread(re, ip)
-	re.thr[tid].mstart = mstart
-	re.thr[tid].mend = mend
-	step(re, tid)
+	-> thr
 }
 
-const kill = {re, tid, msg
+const thrfree = {re, thr
 	/* 
 	   free the dying thread, and shuffle the last
 	   thread into the it's place in the thread list
 	*/
-	trace(re, re.thr[tid], "\t\tkill %z: %s\n", re.thr[tid].uid, msg)
-	std.slfree(re.thr[tid].mstart)
-	std.slfree(re.thr[tid].mend)
-	std.free(re.thr[tid])
-	re.thr[tid] = re.thr[re.nthr - 1]
-	re.nthr--
+	trace(re, thr, "\t\tcleanup %z\n", thr.tid)
+	std.slfree(thr.mstart)
+	std.slfree(thr.mend)
+	std.free(thr)
 }
 
-const finish = {re, tid
-	trace(re, re.thr[tid], "finish\n", tid)
-	match re.matched
-	| `std.None:
-	| `std.Some thr:	std.free(thr)
-	;;
-	re.matched = `std.Some re.thr[tid]
-	re.thr[tid] = re.thr[re.nthr - 1]
-	re.nthr--
-}
-
 const in = {re, str 
 	-> re.strp < str.len
 }
@@ -184,7 +218,6 @@
 
 const trace : (re : regex#, thr : rethread#, msg : byte[:], args : ...) = {re, thr, msg, args
 	if re.debug
-		std.put("\tthr %i: ", thr.uid)
 		std.putv(msg, std.vastart(&args))
 	;;
 }
--- a/types.myr
+++ b/types.myr
@@ -10,15 +10,17 @@
 	;;
 
 	type regex = struct
+		/* compile state */
 		debug	: bool
 		pat	: byte[:]
 		nmatch	: std.size
 
 		/* VM state */
+		runq	: rethread#
+		expired	: rethread#
 		proglen	: std.size
 		prog	: reinst[:]
 		nthr	: std.size
-		thr	: rethread#[:]
 		str	: byte[:]
 		strp	: std.size
 		matched	: std.option(rethread#)
@@ -25,8 +27,12 @@
 	;;
 
 	type rethread = struct
-		uid	: std.size	/* just for debugging */
+		next	: rethread#	/* run queue link */
+
+		tid	: std.size	/* just for debugging */
 		ip	: std.size	/* the instruction pointer */
+		dead	: bool		/* thread died */
+		matched	: bool		/* thread matched */
 
 		mstart	: std.size[:]	/* match starts */
 		mend	: std.size[:]	/* match ends */