Add hs_try_putmvar()
authorSimon Marlow <marlowsd@gmail.com>
Tue, 30 Aug 2016 19:55:10 +0000 (20:55 +0100)
committerSimon Marlow <marlowsd@gmail.com>
Mon, 12 Sep 2016 07:33:24 +0000 (08:33 +0100)
commit454033b54e2f7eef2354cc9d7ae7e7cba4dff09a
tree3577ed7b0b42e2acff1502673e1ee474fba31319
parent0e7ccf6d233c66b23a60de4e35e039f78ea3e162
Add hs_try_putmvar()

Summary:
This is a fast, non-blocking, asynchronous, interface to tryPutMVar that
can be called from C/C++.

It's useful for callback-based C/C++ APIs: the idea is that the callback
invokes hs_try_putmvar(), and the Haskell code waits for the callback to
run by blocking in takeMVar.

The callback doesn't block - this is often a requirement of
callback-based APIs.  The callback wakes up the Haskell thread with
minimal overhead and no unnecessary context-switches.

There are a couple of benchmarks in
testsuite/tests/concurrent/should_run.  Some example results comparing
hs_try_putmvar() with using a standard foreign export:

    ./hs_try_putmvar003 1 64 16 100 +RTS -s -N4     0.49s
    ./hs_try_putmvar003 2 64 16 100 +RTS -s -N4     2.30s

hs_try_putmvar() is 4x faster for this workload (see the source for
hs_try_putmvar003.hs for details of the workload).

An alternative solution is to use the IO Manager for this.  We've tried
it, but there are problems with that approach:
* Need to create a new file descriptor for each callback
* The IO Manger thread(s) become a bottleneck
* More potential for things to go wrong, e.g. throwing an exception in
  an IO Manager callback kills the IO Manager thread.

Test Plan: validate; new unit tests

Reviewers: niteria, erikd, ezyang, bgamari, austin, hvr

Subscribers: thomie

Differential Revision: https://phabricator.haskell.org/D2501
24 files changed:
docs/users_guide/ffi-chap.rst
includes/HsFFI.h
libraries/base/GHC/Conc.hs
libraries/base/GHC/Conc/Sync.hs
rts/Capability.c
rts/Capability.h
rts/Prelude.h
rts/PrimOps.cmm
rts/RtsAPI.c
rts/Schedule.c
rts/Task.c
rts/Task.h
rts/Threads.c
rts/Threads.h
rts/package.conf.in
testsuite/tests/concurrent/should_run/Makefile
testsuite/tests/concurrent/should_run/all.T
testsuite/tests/concurrent/should_run/hs_try_putmvar001.hs [new file with mode: 0644]
testsuite/tests/concurrent/should_run/hs_try_putmvar001.stdout [new file with mode: 0644]
testsuite/tests/concurrent/should_run/hs_try_putmvar001_c.c [new file with mode: 0644]
testsuite/tests/concurrent/should_run/hs_try_putmvar002.hs [new file with mode: 0644]
testsuite/tests/concurrent/should_run/hs_try_putmvar002_c.c [new file with mode: 0644]
testsuite/tests/concurrent/should_run/hs_try_putmvar003.hs [new file with mode: 0644]
testsuite/tests/concurrent/should_run/hs_try_putmvar003_c.c [new file with mode: 0644]