diff options
author | Ori Bernstein <ori@eigenstate.org> | 2017-10-29 19:08:13 -0700 |
---|---|---|
committer | Ori Bernstein <ori@eigenstate.org> | 2017-10-29 19:08:13 -0700 |
commit | 269e4f69372bc1250dcb70a9dfde30486809f1b0 (patch) | |
tree | eb86ec1c691bf8f479be36ede67e029f55f3c09c /lib/thread | |
parent | 4eea6de57c9fce0a69f85270303baae069c3e237 (diff) | |
parent | d359a98ab9cfc42de66ad35333bd6d6c0571b7ca (diff) | |
download | mc-269e4f69372bc1250dcb70a9dfde30486809f1b0.tar.gz |
Merge branch 'master' into qbeqbe
Diffstat (limited to 'lib/thread')
-rw-r--r-- | lib/thread/bld.sub | 15 | ||||
-rw-r--r-- | lib/thread/mutex+openbsd:6.2.myr | 76 | ||||
-rw-r--r-- | lib/thread/ncpu+linux.myr | 30 | ||||
-rw-r--r-- | lib/thread/ncpu+openbsd.myr | 23 | ||||
-rw-r--r-- | lib/thread/ncpu+plan9.myr | 2 | ||||
-rw-r--r-- | lib/thread/spawn+osx.myr | 60 | ||||
-rw-r--r-- | lib/thread/start+osx-x64.s | 41 | ||||
-rw-r--r-- | lib/thread/test/mutex.myr | 1 |
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) |