summaryrefslogtreecommitdiff
path: root/lib/thread
diff options
context:
space:
mode:
Diffstat (limited to 'lib/thread')
-rw-r--r--lib/thread/bld.sub15
-rw-r--r--lib/thread/mutex+openbsd:6.2.myr76
-rw-r--r--lib/thread/ncpu+linux.myr30
-rw-r--r--lib/thread/ncpu+openbsd.myr23
-rw-r--r--lib/thread/ncpu+plan9.myr2
-rw-r--r--lib/thread/spawn+osx.myr60
-rw-r--r--lib/thread/start+osx-x64.s41
-rw-r--r--lib/thread/test/mutex.myr1
8 files changed, 219 insertions, 29 deletions
diff --git a/lib/thread/bld.sub b/lib/thread/bld.sub
index 02e5e50..f386162 100644
--- a/lib/thread/bld.sub
+++ b/lib/thread/bld.sub
@@ -8,16 +8,17 @@ lib thread =
# linux impl of basic thread primitives
#condvar+linux.myr
+ exit+linux-x64.s
mutex+linux.myr
+ ncpu+linux.myr
spawn+linux.myr
- exit+linux-x64.s
# freebsd impl of thread primitives
#condvar+freebsd.myr
+ exit+freebsd-x64.s
mutex+freebsd.myr
- spawn+freebsd.myr
ncpu+freebsd.myr
- exit+freebsd-x64.s
+ spawn+freebsd.myr
# netbsd impl of thread primitives
#condvar+netbsd.myr
@@ -33,14 +34,16 @@ lib thread =
# 9front impl of thread primitives
#condvar+plan9.myr
+ atomic-impl+plan9-x64.s
mutex+plan9.myr
- spawn+plan9.myr
ncpu+plan9.myr
- atomic-impl+plan9-x64.s
+ spawn+plan9.myr
# openbsd impl of thread primitives
- spawn+openbsd.myr
exit+openbsd-x64.s
+ mutex+openbsd:6.2.myr
+ ncpu+openbsd.myr
+ spawn+openbsd.myr
atomic-impl+x64.s
atomic.myr
diff --git a/lib/thread/mutex+openbsd:6.2.myr b/lib/thread/mutex+openbsd:6.2.myr
new file mode 100644
index 0000000..f2648f5
--- /dev/null
+++ b/lib/thread/mutex+openbsd:6.2.myr
@@ -0,0 +1,76 @@
+use std
+use sys
+
+use "atomic"
+use "common"
+
+pkg thread =
+ type mutex = struct
+ _state : uint32
+ ;;
+
+ const mkmtx : (-> mutex)
+ const mtxlock : (mtx : mutex# -> void)
+ const mtxtrylock : (mtx : mutex# -> bool)
+ const mtxunlock : (mtx : mutex# -> void)
+
+ pkglocal const Unlocked : uint32 = 0
+ pkglocal const Locked : uint32 = 1
+ pkglocal const Contended : uint32 = 2
+;;
+
+var nspin = 10 /* FIXME: pick a sane number, based on CPU count */
+
+const mkmtx = {
+ -> [._state = Unlocked]
+}
+
+const mtxlock = {mtx
+ var c
+
+ /*
+ Uncontended case: we get an unlocked mutex, and we lock it.
+ */
+ c = Locked
+ for var i = 0; i < nspin; i++
+ c = xcas(&mtx._state, Unlocked, Locked)
+ if c == Unlocked
+ -> void
+ ;;
+ ;;
+
+ /*
+ Contended case: we set the lock state to Contended. This indicates that there
+ the lock is locked, and we potentially have threads waiting on it, which means
+ that we will need to wake them up.
+ */
+ if c == Locked
+ c = xchg(&mtx._state, Contended)
+ ;;
+
+ while c != Unlocked
+ sys.futex(&mtx._state, sys.Futexwait, (Contended : int), Zptr, Zptr)
+ c = xchg(&mtx._state, Contended)
+ ;;
+}
+
+const mtxtrylock = {mtx
+ -> xcas(&mtx._state, Unlocked, Locked) == Unlocked
+}
+
+const mtxunlock = {mtx
+ /*
+ Uncontended case: If the mutex state is not contended, and we still
+ are uncontended by the xchg() call, then it's safe to simply return;
+ nobody was waiting for us.
+ */
+ if mtx._state == Contended
+ mtx._state = Unlocked
+ elif xchg(&mtx._state, Unlocked) == Locked
+ -> void
+ ;;
+
+ /* wake one thread */
+ sys.futex(&mtx._state, sys.Futexwake, 1, Zptr, Zptr)
+}
+
diff --git a/lib/thread/ncpu+linux.myr b/lib/thread/ncpu+linux.myr
new file mode 100644
index 0000000..5c2ea15
--- /dev/null
+++ b/lib/thread/ncpu+linux.myr
@@ -0,0 +1,30 @@
+use std
+use sys
+
+pkg thread =
+ const ncpu : (-> int)
+;;
+
+const ncpu = {
+ var cpubuf : uint64[4]
+ var n
+
+ sys.sched_getaffinity(sys.getpid(), sizeof(uint64[4]), (&cpubuf : uint64#))
+ n = 0
+ for b : cpubuf[:]
+ if b != 0
+ n += count(b)
+ ;;
+ ;;
+ -> n
+}
+
+const count = {b
+ var n = 0
+ for var i = 0; i < 8*sizeof(uint64); i++
+ if b & (1<<i) != 0
+ n++
+ ;;
+ ;;
+ -> n
+}
diff --git a/lib/thread/ncpu+openbsd.myr b/lib/thread/ncpu+openbsd.myr
new file mode 100644
index 0000000..1aa3dc1
--- /dev/null
+++ b/lib/thread/ncpu+openbsd.myr
@@ -0,0 +1,23 @@
+use std
+use sys
+
+pkg thread =
+ const ncpu : (-> int)
+;;
+
+const ncpu = {
+ var mib : int[2]
+ var ncpu : int
+ var ncpusz
+ var res
+
+ mib[0] = 6 /* CTL_HW */
+ mib[1] = 3 /* HW_NCPU */
+ ncpusz = sizeof(int)
+
+ res = sys.sysctl(mib[:], (&ncpu : void#), &ncpusz, (0 : void#), (0 : sys.size#))
+ if res < 0 || ncpu <= 0
+ -> 1
+ ;;
+ -> ncpu
+}
diff --git a/lib/thread/ncpu+plan9.myr b/lib/thread/ncpu+plan9.myr
index 25d09cb..a13725c 100644
--- a/lib/thread/ncpu+plan9.myr
+++ b/lib/thread/ncpu+plan9.myr
@@ -5,7 +5,7 @@ pkg thread =
;;
const ncpu = {
- match std.intparse(std.getenvv("NPROC", ""))
+ match std.intparse(std.getenvv("NPROC", "1"))
| `std.Some n: -> n
| `std.None: -> 1
;;
diff --git a/lib/thread/spawn+osx.myr b/lib/thread/spawn+osx.myr
index bedaa42..4e99598 100644
--- a/lib/thread/spawn+osx.myr
+++ b/lib/thread/spawn+osx.myr
@@ -34,15 +34,41 @@ const spawn = {fn
}
const spawnstk = {fn, sz
- var tid : tid, ret
+ var stk : byte#, tid, ret
+ var szp, f, tos, env, envsz
+ stk = getstk(sz)
+ if stk == sys.Mapbad
+ -> `std.Err "couldn't get stack"
+ ;;
+ tid = -1
+
+ /* find top of stack */
+ tos = (stk : std.intptr) + (sz : std.intptr)
+
+ /* store the stack size */
+ tos -= sizeof(sys.size)
+ sz -= sizeof(sys.size)
+ szp = (tos : sys.size#)
+ szp# = Stacksz
+
+ /* store the function we call */
+ envsz = std.fnenvsz(fn)
+ tos -= (envsz : std.intptr)
+ sz -= (envsz : sys.size)
+ env = tos
+ tos -= sizeof((->void))
+ sz -= sizeof((->void))
+ f = (tos : (->void)#)
+ f# = std.fnbdup(fn, (env : byte#)[:envsz])
+ var repr = (&fn : int64[2]#)#
ret = sys.bsdthread_create( \
- (fn : void#), \
- envptr(&fn), \
- (sz : void#), \
- (0 : void#), \
- 0)
+ (tramp : void#), \ /* start */
+ (tos : void#), \ /* arg */
+ (tos : void#), \ /* stack */
+ (0 : void#), \ /* pthread struct */
+ 0x01000000) /* flags (PTHREAD_START_CUSTOM): don't alloc stack in kernel */
if ret == (-1 : void#)
-> `std.Err "couldn't spawn thread"
@@ -50,10 +76,24 @@ const spawnstk = {fn, sz
-> `std.Ok (ret : tid)
}
-const envptr = {fn
- var repr : std.intptr[2]
+const getstk = {sz
+ var p, m
- repr = (fn : std.intptr[2]#)#
- -> (repr[0] : void#)
+ std.put("allocating stack {x}\n", sz)
+ p = sys.mmap((0 : byte#), sz, sys.Mprotrw, sys.Mpriv | sys.Manon, -1, 0)
+ if p == sys.Mapbad
+ -> p
+ ;;
+ m = (p : std.intptr)
+ -> (m : byte#)
}
+/*
+ thread trampoline, called by `start`. We set up the args
+ for the closure and env on the stack, and then we call it
+ from here, doing the cleanup and exit at the end.
+*/
+const tramp = {f : (-> void)#
+ f#()
+ exit()
+}
diff --git a/lib/thread/start+osx-x64.s b/lib/thread/start+osx-x64.s
index bc62d08..bb497bb 100644
--- a/lib/thread/start+osx-x64.s
+++ b/lib/thread/start+osx-x64.s
@@ -1,22 +1,41 @@
-// The entry point for thread start, registered with bsdthread_register
-// %rdi: pthread (0, for us)
-// %rsi: mach thread port (ignored)
-// %rdx: func
-// %rcx: env
-// %r8: stack
-// %r9: flags (= 0)
-// %rsp: stack - C_64_REDZONE_LEN (= stack - 128)
+# The entry point for thread start, registered with bsdthread_register
+# %rdi: pthread (0, for us)
+# %rsi: mach thread port (ignored)
+# %rdx: func
+# %rcx: env
+# %r8: stack
+# %r9: flags (= 0)
+# %rsp: stack - C_64_REDZONE_LEN (= stack - 128)
.globl _thread$start
_thread$start:
/* call the function */
-# movq %r8, %rsp /* set up stack */
- movq %rcx, %rax /* set up env */
+ movq %r8, %rsp /* set up stack */
+ movq %rcx,%rdi
callq *%rdx /* call function */
+
+/*
+const thread.exit : (stacksz : std.size -> void)
+NOTE: must be called from the bottom of the stack, since
+we assume that %rbp is in the top 4k of the stack.
+*/
+.globl _thread$exit
+_thread$exit:
+ /* find top of stack */
+ movq %rbp,%rdi /* addr */
+ andq $~0xfff,%rdi /* align it */
+ addq $0x1000,%rdi
+
+ /* munmap(base, size) */
+ movq $0x2000049,%rax /* munmap */
+ movq -8(%rdi),%rsi /* size */
+ subq %rsi,%rdi /* move to base ptr */
+ syscall
/* exit the thread */
movq $0x2000169, %rax /* Sysbsdthread_terminate */
- movq %rsp, %rdi /* stack */
+ movq $0, %rdi /* stack */
movq $0, %rsi /* len */
movq $0, %rdx /* sem */
syscall
+
diff --git a/lib/thread/test/mutex.myr b/lib/thread/test/mutex.myr
index eb15a5e..fd58df1 100644
--- a/lib/thread/test/mutex.myr
+++ b/lib/thread/test/mutex.myr
@@ -27,7 +27,6 @@ const incvar = {
for var i = 0; i < 1000; i++
thread.mtxlock(&mtx)
val++
- std.put("val: {}\n", val)
thread.mtxunlock(&mtx)
;;
thread.xadd(&done, 1)