shithub: mc

Download patch

ref: 183f3d40a1dbc2254f1e01de21eb022996f40ad2
parent: e70e83ae4362b60e9eb2134fb5d388576ee90bdf
author: Ori Bernstein <ori@eigenstate.org>
date: Sat Nov 3 12:26:58 EDT 2018

First attempt at a queue API.

	Simple, naive, but seems to work.

--- a/lib/thread/bld.sub
+++ b/lib/thread/bld.sub
@@ -5,6 +5,7 @@
 	# higher level apis
 	future.myr
 	do.myr
+	queue.myr
 
 	# generic fallbacks
 	condvar.myr
--- /dev/null
+++ b/lib/thread/queue.myr
@@ -1,0 +1,65 @@
+use std
+use "mutex"
+use "condvar"
+
+pkg thread =
+	type queue(@a) = struct
+		hd	: qnode(@a)#
+		tl	: qnode(@a)#
+		mtx	: mutex
+		cv	: cond
+	;;
+
+	type qnode(@a) = struct
+		v	: @a
+		next	: qnode(@a)#
+	;;
+
+	generic qinit	: (q : queue(@a)# -> void)
+	generic qget	: (q : queue(@a)# -> @a)
+	generic qput	: (q : queue(@a)#, v : @a -> void)
+;;
+
+generic Znode = (0 : qnode(@a)#)
+
+generic qinit = {q
+	q.hd = Znode
+	q.tl = Znode
+	q.mtx = mkmtx()
+	q.cv = mkcond(&q.mtx)
+}
+
+
+generic qput = {q, v : @a
+	var n : qnode(@a)#
+
+	n = std.mk([.next=Znode, .v=v])
+	mtxlock(&q.mtx)
+	if q.hd == Znode
+		q.hd = n
+		q.tl = n
+	else
+		q.tl.next = n
+		q.tl = n
+	;;
+	condsignal(&q.cv)
+	mtxunlock(&q.mtx)
+}
+
+generic qget = {q
+	var n, v
+
+	mtxlock(&q.mtx)
+:again
+	if q.hd == Znode
+		condwait(&q.cv)
+		goto again
+	else
+		n = q.hd
+		q.hd = q.hd.next
+	;;
+	mtxunlock(&q.mtx)
+	v = n.v
+	std.free(n)
+	-> v
+}
--- /dev/null
+++ b/lib/thread/test/queue.myr
@@ -1,0 +1,46 @@
+use std
+use thread
+use testr
+
+const Nproduced = 100
+
+const main = {
+	testr.run([
+		[.name="simple-singlethreaded", .fn=simple],
+		[.name="slow-producer", .fn={ctx; producerconsumer(ctx, 100, 100)}],
+		[.name="fast-producer", .fn={ctx; producerconsumer(ctx, 10_000, 0)}],
+	][:])
+}
+
+const simple = {ctx
+	var q
+	
+	/* simple test */
+	thread.qinit(&q)
+	thread.qput(&q, 123)
+	thread.qput(&q, 246)
+
+	testr.check(ctx, thread.qget(&q) == 123, "expected 123")
+	testr.check(ctx, thread.qget(&q) == 246, "expected 246")
+}
+
+const producerconsumer = {ctx, count, delay
+	var qp
+
+	qp = std.alloc()
+	thread.qinit(qp)
+	thread.spawn({; producer(qp, count, delay)})
+
+	for var i = 0; i < count; i++
+		testr.check(ctx, thread.qget(qp) == i, "expected {}\n", i)
+	;;
+}
+
+const producer = {qp, count, delay
+	for var i = 0; i < count; i++
+		thread.qput(qp, i)
+		if delay > 0
+			std.usleep(delay)
+		;;
+	;;
+}