The In_thread
module has functions for interaction between the Async world and other
(kernel) threads. The name is to remind us to think about threads and race
conditions.
All threads come from the one thread pool used for all Async-managed threads.
module Priority : module type of Core.Linux_ext.Priority with type Priority.t = Core.Linux_ext.Priority.t
module Helper_thread : sig ... end
val pipe_of_squeue : 'a Core.Squeue.t ‑> 'a Async_kernel.Pipe.Reader.t
pipe_of_squeue squeue
returns a pipe p
and consumes the contents squeue
, placing
them in p
. It repeatedly grabs everything from squeue
, places it in p
, and
then waits for pushback on p
.
val run : ?priority:Priority.t ‑> ?thread:Helper_thread.t ‑> ?when_finished:[ `Take_the_async_lock | `Notify_the_scheduler | `Best ] ‑> ?name:string ‑> (unit ‑> 'a) ‑> 'a Async_kernel.Deferred.t
run ?priority ?thread ?name f
runs f ()
in a separate thread outside Async and
returns the result as a Deferred in the Async world. If f ()
raises an exception
(asynchronously, since it is another thread) then that exception will be raised to the
monitor that called run
.
WARNING: Async code MUST NOT be used from within f
. By Async code we mean
pretty-much all functions of libraries making use of Async. Only a few functions of
the Async library can be called inside In_thread.run
. These are explicitly marked
as such, using the phrase "thread-safe".
If thread
is not supplied, then any thread from the thread pool could be used. If
you need to run routines in a specific thread (as is required by some libraries like
Sqlite), you should create a helper thread and supply it to run
.
If priority
is supplied, the priority of the thread in the linux scheduler will be
set to priority
for the duration of f ()
, provided the thread is allowed to do so
(see man setpriority
).
If you call run
several times with the same helper thread, the f ()
calls will run
in sequence, in the order in which they are supplied to run
. Each f ()
will
complete (return or raise) before another f ()
starts.
For example, if you do:
let () =
run ~thread f1;
run ~thread f2;
run ~thread f3;
Then the thread will run f1 ()
to completion, then f2 ()
to completion, then
f3 ()
to completion.
If name
is supplied, the name of the thread will be set to it for the duration of
the execution of f ()
.
when_finished
describes how the helper thread behaves once f ()
has completed:
`Take_the_lock
it takes the Async lock and runs a cycle immediately`Notify_the_scheduler
it just notifies the scheduler that the result is ready`Best
it tries to take the lock and run a cycle, but will fallback to
`Notify_the_scheduler
method if the Async lock is already held by someone else.
The default is `Best
, and one shouldn't need to change it -- it is useful only
for unit testing.val syscall : name:string ‑> (unit ‑> 'a) ‑> ('a, exn) Core.Result.t Async_kernel.Deferred.t
syscall f
runs f, which should be a single system call, and returns the result,
handling the restarting of interrupted system calls. To avoid race conditions, the
f
supplied to syscall
should just make a system call. That way, everything else
is done holding the Async lock.
val syscall_exn : name:string ‑> (unit ‑> 'a) ‑> 'a Async_kernel.Deferred.t