xref: /netbsd-src/sys/rump/share/man/man3/rumpuser.3 (revision 918835f5c686a7f0379246d8b9f47d768fe512eb)
1.\"     $NetBSD: rumpuser.3,v 1.4 2023/07/14 23:21:53 lukem Exp $
2.\"
3.\" Copyright (c) 2013 Antti Kantee.  All rights reserved.
4.\"
5.\" Redistribution and use in source and binary forms, with or without
6.\" modification, are permitted provided that the following conditions
7.\" are met:
8.\" 1. Redistributions of source code must retain the above copyright
9.\"    notice, this list of conditions and the following disclaimer.
10.\" 2. Redistributions in binary form must reproduce the above copyright
11.\"    notice, this list of conditions and the following disclaimer in the
12.\"    documentation and/or other materials provided with the distribution.
13.\"
14.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24.\" SUCH DAMAGE.
25.\"
26.Dd July 15, 2023
27.Dt RUMPUSER 3
28.Os
29.Sh NAME
30.Nm rumpuser
31.Nd rump kernel hypercall interface
32.Sh LIBRARY
33rump User Library (librumpuser, \-lrumpuser)
34.Sh SYNOPSIS
35.In rump/rumpuser.h
36.Sh DESCRIPTION
37The
38.Nm
39hypercall interfaces allow a rump kernel to access host resources.
40A hypervisor implementation must implement the routines described in
41this document to allow a rump kernel to run on the host.
42The implementation included in
43.Nx
44is for POSIX-like hosts (*BSD, Linux, etc.).
45This document is divided into sections based on the functionality
46group of each hypercall.
47.Pp
48Since the hypercall interface is a C function interface, both the
49rump kernel and the hypervisor must conform to the same ABI.
50The interface itself attempts to assume as little as possible from
51the type systems, and for example
52.Vt off_t
53is passed as
54.Vt int64_t
55and enums are passed as ints.
56It is recommended that the hypervisor converts these to the native
57types before starting to process the hypercall, for example by
58assigning the ints back to enums.
59.Sh UPCALLS AND RUMP KERNEL CONTEXT
60A hypercall is always entered with the calling thread scheduled in
61the rump kernel.
62In case the hypercall intends to block while waiting for an event,
63the hypervisor must first release the rump kernel scheduling context.
64In other words, the rump kernel context is a resource and holding
65on to it while waiting for a rump kernel event/resource may lead
66to a deadlock.
67Even when there is no possibility of deadlock in the strict sense
68of the term, holding on to the rump kernel context while performing
69a slow hypercall such as reading a device will prevent other threads
70(including the clock interrupt) from using that rump kernel context.
71.Pp
72Releasing the context is done by calling the
73.Fn hyp_backend_unschedule
74upcall which the hypervisor received from rump kernel as a parameter
75for
76.Fn rumpuser_init .
77Before a hypercall returns back to the rump kernel, the returning thread
78must carry a rump kernel context.
79In case the hypercall unscheduled itself, it must reschedule itself
80by calling
81.Fn hyp_backend_schedule .
82.Sh HYPERCALL INTERFACES
83.Ss Initialization
84.Ft int
85.Fn rumpuser_init "int version" "struct rump_hyperup *hyp"
86.Pp
87Initialize the hypervisor.
88.Bl -tag -width "xenum_rumpclock"
89.It Fa version
90hypercall interface version number that the kernel expects to be used.
91In case the hypervisor cannot provide an exact match, this routine must
92return a non-zero value.
93.It Fa hyp
94pointer to a set of upcalls the hypervisor can make into the rump kernel
95.El
96.Ss Memory allocation
97.Ft int
98.Fn rumpuser_malloc "size_t len" "int alignment" "void **memp"
99.Bl -tag -width "xenum_rumpclock"
100.It Fa len
101amount of memory to allocate
102.It Fa alignment
103size the returned memory must be aligned to.
104For example, if the value passed is 4096, the returned memory
105must be aligned to a 4k boundary.
106.It Fa memp
107return pointer for allocated memory
108.El
109.Pp
110.Ft void
111.Fn rumpuser_free "void *mem" "size_t len"
112.Bl -tag -width "xenum_rumpclock"
113.It Fa mem
114memory to free
115.It Fa len
116length of allocation.
117This is always equal to the amount the caller requested from the
118.Fn rumpuser_malloc
119which returned
120.Fa mem .
121.El
122.Ss Files and I/O
123.Ft int
124.Fn rumpuser_open "const char *name" "int mode" "int *fdp"
125.Pp
126Open
127.Fa name
128for I/O and associate a file descriptor with it.
129Notably, there needs to be no mapping between
130.Fa name
131and the host's file system namespace.
132For example, it is possible to associate the file descriptor with
133device I/O registers for special values of
134.Fa name .
135.Bl -tag -width "xenum_rumpclock"
136.It Fa name
137the identifier of the file to open for I/O
138.It Fa mode
139combination of the following:
140.Bl -tag -width "XRUMPUSER_OPEN_CREATE"
141.It Dv RUMPUSER_OPEN_RDONLY
142open only for reading
143.It Dv RUMPUSER_OPEN_WRONLY
144open only for writing
145.It Dv RUMPUSER_OPEN_RDWR
146open for reading and writing
147.It Dv RUMPUSER_OPEN_CREATE
148do not treat missing
149.Fa name
150as an error
151.It Dv RUMPUSER_OPEN_EXCL
152combined with
153.Dv RUMPUSER_OPEN_CREATE ,
154flag an error if
155.Fa name
156already exists
157.It Dv RUMPUSER_OPEN_BIO
158the caller will use this file for block I/O, usually used in
159conjunction with accessing file system media.
160The hypervisor should treat this flag as advisory and possibly
161enable some optimizations for
162.Fa *fdp
163based on it.
164.El
165Notably, the permissions of the created file are left up to the
166hypervisor implementation.
167.It Fa fdp
168An integer value denoting the open file is returned here.
169.El
170.Pp
171.Ft int
172.Fn rumpuser_close "int fd"
173.Pp
174Close a previously opened file descriptor.
175.Pp
176.Ft int
177.Fn rumpuser_getfileinfo "const char *name" "uint64_t *size" "int *type"
178.Bl -tag -width "xenum_rumpclock"
179.It Fa name
180file for which information is returned.
181The namespace is equal to that of
182.Fn rumpuser_open .
183.It Fa size
184If
185.Pf non- Dv NULL ,
186size of the file is returned here.
187.It Fa type
188If
189.Pf non- Dv NULL ,
190type of the file is returned here.
191The options are
192.Dv RUMPUSER_FT_DIR ,
193.Dv RUMPUSER_FT_REG ,
194.Dv RUMPUSER_FT_BLK ,
195.Dv RUMPUSER_FT_CHR ,
196or
197.Dv RUMPUSER_FT_OTHER
198for directory, regular file, block device, character device or unknown,
199respectively.
200.El
201.Pp
202.Ft void
203.Fo rumpuser_bio
204.Fa "int fd" "int op" "void *data" "size_t dlen" "int64_t off"
205.Fa "rump_biodone_fn biodone" "void *donearg"
206.Fc
207.Pp
208Initiate block I/O and return immediately.
209.Bl -tag -width "xenum_rumpclock"
210.It Fa fd
211perform I/O on this file descriptor.
212The file descriptor must have been opened with
213.Dv RUMPUSER_OPEN_BIO .
214.It Fa op
215Transfer data from the file descriptor with
216.Dv RUMPUSER_BIO_READ
217and transfer data to the file descriptor with
218.Dv RUMPUSER_BIO_WRITE .
219Unless
220.Dv RUMPUSER_BIO_SYNC
221is specified, the hypervisor may cache a write instead of
222committing it to permanent storage.
223.It Fa data
224memory address to transfer data to/from
225.It Fa dlen
226length of I/O.
227The length is guaranteed to be a multiple of 512.
228.It Fa off
229offset into
230.Fa fd
231where I/O is performed
232.It Fa biodone
233To be called when the I/O is complete.
234Accessing
235.Fa data
236is not legal after the call is made.
237.It Fa donearg
238opaque arg that must be passed to
239.Fa biodone .
240.El
241.Pp
242.Ft int
243.Fo rumpuser_iovread
244.Fa "int fd" "struct rumpuser_iovec *ruiov" "size_t iovlen"
245.Fa "int64_t off" "size_t *retv"
246.Fc
247.Pp
248.Ft int
249.Fo rumpuser_iovwrite
250.Fa "int fd" "struct rumpuser_iovec *ruiov" "size_t iovlen"
251.Fa "int64_t off" "size_t *retv"
252.Fc
253.Pp
254These routines perform scatter-gather I/O which is not
255block I/O by nature and therefore cannot be handled by
256.Fn rumpuser_bio .
257.Bl -tag -width "xenum_rumpclock"
258.It Fa fd
259file descriptor to perform I/O on
260.It Fa ruiov
261an array of I/O descriptors.
262It is defined as follows:
263.Bd -literal -offset indent -compact
264struct rumpuser_iovec {
265	void *iov_base;
266	size_t iov_len;
267};
268.Ed
269.It Fa iovlen
270number of elements in
271.Fa ruiov
272.It Fa off
273offset of
274.Fa fd
275to perform I/O on.
276This can either be a non-negative value or
277.Dv RUMPUSER_IOV_NOSEEK .
278The latter denotes that no attempt to change the underlying objects
279offset should be made.
280Using both types of offsets on a single instance of
281.Fa fd
282results in undefined behavior.
283.It Fa retv
284number of bytes successfully transferred is returned here
285.El
286.Pp
287.Ft int
288.Fo rumpuser_syncfd
289.Fa "int fd" "int flags" "uint64_t start" "uint64_t len"
290.Fc
291.Pp
292Synchronizes
293.Fa fd
294with respect to backing storage.
295The other arguments are:
296.Bl -tag -width "xenum_rumpclock"
297.It Fa flags
298controls how synchronization happens.
299It must contain one of the following:
300.Bl -tag -width "XRUMPUSER_SYNCFD_BARRIER"
301.It Dv RUMPUSER_SYNCFD_READ
302Make sure that the next read sees writes from all other parties.
303This is useful for example in the case that
304.Fa fd
305represents memory to write a DMA read is being performed.
306.It Dv RUMPUSER_SYNCFD_WRITE
307Flush cached writes.
308.El
309.Pp
310The following additional parameters may be passed in
311.Fa flags :
312.Bl -tag -width "XRUMPUSER_SYNCFD_BARRIER"
313.It Dv RUMPUSER_SYNCFD_BARRIER
314Issue a barrier.
315Outstanding I/O operations which were started before the barrier
316complete before any operations after the barrier are performed.
317.It Dv RUMPUSER_SYNCFD_SYNC
318Wait for the synchronization operation to fully complete before
319returning.
320For example, this could mean that the data to be written to a disk
321has hit either the disk or non-volatile memory.
322.El
323.It Fa start
324offset into the object.
325.It Fa len
326the number of bytes to synchronize.
327The value 0 denotes until the end of the object.
328.El
329.Ss Clocks
330The hypervisor should support two clocks, one for wall time and one
331for monotonically increasing time, the latter of which may be based
332on some arbitrary time (e.g. system boot time).
333If this is not possible, the hypervisor must make a reasonable effort to
334retain semantics.
335.Pp
336.Ft int
337.Fn rumpuser_clock_gettime "int enum_rumpclock" "int64_t *sec" "long *nsec"
338.Bl -tag -width "xenum_rumpclock"
339.It Fa enum_rumpclock
340specifies the clock type.
341In case of
342.Dv RUMPUSER_CLOCK_RELWALL
343the wall time should be returned.
344In case of
345.Dv RUMPUSER_CLOCK_ABSMONO
346the time of a monotonic clock should be returned.
347.It Fa sec
348return value for seconds
349.It Fa nsec
350return value for nanoseconds
351.El
352.Pp
353.Ft int
354.Fn rumpuser_clock_sleep "int enum_rumpclock" "int64_t sec" "long nsec"
355.Bl -tag -width "xenum_rumpclock"
356.It Fa enum_rumpclock
357In case of
358.Dv RUMPUSER_CLOCK_RELWALL ,
359the sleep should last at least as long as specified.
360In case of
361.Dv RUMPUSER_CLOCK_ABSMONO ,
362the sleep should last until the hypervisor monotonic clock hits
363the specified absolute time.
364.It Fa sec
365sleep duration, seconds.
366exact semantics depend on
367.Fa clk .
368.It Fa nsec
369sleep duration, nanoseconds.
370exact semantics depend on
371.Fa clk .
372.El
373.Ss Parameter retrieval
374.Ft int
375.Fn rumpuser_getparam "const char *name" "void *buf" "size_t buflen"
376.Pp
377Retrieve a configuration parameter from the hypervisor.
378It is up to the hypervisor to decide how the parameters can be set.
379.Bl -tag -width "xenum_rumpclock"
380.It Fa name
381name of the parameter.
382If the name starts with an underscore, it means a mandatory parameter.
383The mandatory parameters are
384.Dv RUMPUSER_PARAM_NCPU
385which specifies the amount of virtual CPUs bootstrapped by the
386rump kernel and
387.Dv RUMPUSER_PARAM_HOSTNAME
388which returns a preferably unique instance name for the rump kernel.
389.It Fa buf
390buffer to return the data in as a string
391.It Fa buflen
392length of buffer
393.El
394.Ss Termination
395.Ft void
396.Fn rumpuser_exit "int value"
397.Pp
398Terminate the rump kernel with exit value
399.Fa value .
400If
401.Fa value
402is
403.Dv RUMPUSER_PANIC
404the hypervisor should attempt to provide something akin to a core dump.
405.Ss Console output
406Console output is divided into two routines: a per-character
407one and printf-like one.
408The former is used e.g. by the rump kernel's internal printf
409routine.
410The latter can be used for direct debug prints e.g. very early
411on in the rump kernel's bootstrap or when using the in-kernel
412routine causes too much skew in the debug print results
413(the hypercall runs outside of the rump kernel and therefore does not
414cause any locking or scheduling events inside the rump kernel).
415.Pp
416.Ft void
417.Fn rumpuser_putchar "int ch"
418.Pp
419Output
420.Fa ch
421on the console.
422.Pp
423.Ft void
424.Fn rumpuser_dprintf "const char *fmt" "..."
425.Pp
426Do output based on printf-like parameters.
427.Ss Signals
428A rump kernel should be able to send signals to client programs
429due to some standard interfaces including signal delivery in their
430specifications.
431Examples of these interfaces include
432.Xr setitimer 2
433and
434.Xr write 2 .
435The
436.Fn rumpuser_kill
437function advises the hypercall implementation to raise a signal for the
438process containing the rump kernel.
439.Pp
440.Ft int
441.Fn rumpuser_kill "int64_t pid" "int sig"
442.Bl -tag -width "xenum_rumpclock"
443.It Fa pid
444The pid of the rump kernel process that the signal is directed to.
445This value may be used as the hypervisor as a hint on how to deliver
446the signal.
447The value
448.Dv RUMPUSER_PID_SELF
449may also be specified to indicate no hint.
450This value will be removed in a future version of the hypercall interface.
451.It Fa sig
452Number of signal to raise.
453The value is in
454.Nx
455signal number namespace.
456In case the host has a native representation for signals, the
457value should be translated before the signal is raised.
458In case there is no mapping between
459.Fa sig
460and native signals (if any), the behavior is implementation-defined.
461.El
462.Pp
463A rump kernel will ignore the return value of this hypercall.
464The only implication of not implementing
465.Fn rumpuser_kill
466is that some application programs may not experience expected behavior
467for standard interfaces.
468.Pp
469As an aside,the
470.Xr rump_sp 7
471protocol provides equivalent functionality for remote clients.
472.Ss Random pool
473.Ft int
474.Fn rumpuser_getrandom "void *buf" "size_t buflen" "int flags" "size_t *retp"
475.Bl -tag -width "xenum_rumpclock"
476.It Fa buf
477buffer that the randomness is written to
478.It Fa buflen
479number of bytes of randomness requested
480.It Fa flags
481The value 0 or a combination of
482.Dv RUMPUSER_RANDOM_HARD
483(return true randomness instead of something from a PRNG)
484and
485.Dv RUMPUSER_RANDOM_NOWAIT
486(do not block in case the requested amount of bytes is not available).
487.It Fa retp
488The number of random bytes written into
489.Fa buf .
490.El
491.Ss Threads
492.Ft int
493.Fo rumpuser_thread_create
494.Fa "void *(*fun)(void *)" "void *arg" "const char *thrname" "int mustjoin"
495.Fa "int priority" "int cpuidx" "void **cookie"
496.Fc
497.Pp
498Create a schedulable host thread context.
499The rump kernel will call this interface when it creates a kernel thread.
500The scheduling policy for the new thread is defined by the hypervisor.
501In case the hypervisor wants to optimize the scheduling of the
502threads, it can perform heuristics on the
503.Fa thrname ,
504.Fa priority
505and
506.Fa cpuidx
507parameters.
508.Bl -tag -width "xenum_rumpclock"
509.It Fa fun
510function that the new thread must call.
511This call will never return.
512.It Fa arg
513argument to be passed to
514.Fa fun
515.It Fa thrname
516Name of the new thread.
517.It Fa mustjoin
518If 1, the thread will be waited for by
519.Fn rumpuser_thread_join
520when the thread exits.
521.It Fa priority
522The priority that the kernel requested the thread to be created at.
523Higher values mean higher priority.
524The exact kernel semantics for each value are not available through
525this interface.
526.It Fa cpuidx
527The index of the virtual CPU that the thread is bound to, or \-1
528if the thread is not bound.
529The mapping between the virtual CPUs and physical CPUs, if any,
530is hypervisor implementation specific.
531.It Fa cookie
532In case
533.Fa mustjoin
534is set, the value returned in
535.Fa cookie
536will be passed to
537.Fn rumpuser_thread_join .
538.El
539.Pp
540.Ft void
541.Fn rumpuser_thread_exit "void"
542.Pp
543Called when a thread created with
544.Fn rumpuser_thread_create
545exits.
546.Pp
547.Ft int
548.Fn rumpuser_thread_join "void *cookie"
549.Pp
550Wait for a joinable thread to exit.
551The cookie matches the value from
552.Fn rumpuser_thread_create .
553.Pp
554.Ft void
555.Fn rumpuser_curlwpop "int enum_rumplwpop" "struct lwp *l"
556.Pp
557Manipulate the hypervisor's thread context database.
558The possible operations are create, destroy, and set as specified by
559.Fa enum_rumplwpop :
560.Bl -tag -width "XRUMPUSER_LWP_DESTROY"
561.It Dv RUMPUSER_LWP_CREATE
562Inform the hypervisor that
563.Fa l
564is now a valid thread context which may be set.
565A currently valid value of
566.Fa l
567may not be specified.
568This operation is informational and does not mandate any action
569from the hypervisor.
570.It Dv RUMPUSER_LWP_DESTROY
571Inform the hypervisor that
572.Fa l
573is no longer a valid thread context.
574This means that it may no longer be set as the current context.
575A currently set context or an invalid one may not be destroyed.
576This operation is informational and does not mandate any action
577from the hypervisor.
578.It Dv RUMPUSER_LWP_SET
579Set
580.Fa l
581as the current host thread's rump kernel context.
582A previous context must not exist.
583.It Dv RUMPUSER_LWP_CLEAR
584Clear the context previous set by
585.Dv RUMPUSER_LWP_SET .
586The value passed in
587.Fa l
588is the current thread and is never
589.Dv NULL .
590.El
591.Pp
592.Ft struct lwp *
593.Fn rumpuser_curlwp "void"
594.Pp
595Retrieve the rump kernel thread context associated with the current host
596thread, as set by
597.Fn rumpuser_curlwpop .
598This routine may be called when a context is not set and
599the routine must return
600.Dv NULL
601in that case.
602This interface is expected to be called very often.
603Any optimizations pertaining to the execution speed of this routine
604should be done in
605.Fn rumpuser_curlwpop .
606.Pp
607.Ft void
608.Fn rumpuser_seterrno "int errno"
609.Pp
610Set an errno value in the calling thread's TLS.
611Note: this is used only if rump kernel clients make rump system calls.
612.Ss Mutexes, rwlocks and condition variables
613The locking interfaces have standard semantics, so we will not
614discuss each one in detail.
615The data types
616.Vt struct rumpuser_mtx ,
617.Vt struct rumpuser_rw
618and
619.Vt struct rumpuser_cv
620used by these interfaces are opaque to the rump kernel, i.e. the
621hypervisor has complete freedom over them.
622.Pp
623Most of these interfaces will (and must) relinquish the rump kernel
624CPU context in case they block (or intend to block).
625The exceptions are the "nowrap" variants of the interfaces which
626may not relinquish rump kernel context.
627.Pp
628.Ft void
629.Fn rumpuser_mutex_init "struct rumpuser_mtx **mtxp" "int flags"
630.Pp
631.Ft void
632.Fn rumpuser_mutex_enter "struct rumpuser_mtx *mtx"
633.Pp
634.Ft void
635.Fn rumpuser_mutex_enter_nowrap "struct rumpuser_mtx *mtx"
636.Pp
637.Ft int
638.Fn rumpuser_mutex_tryenter "struct rumpuser_mtx *mtx"
639.Pp
640.Ft void
641.Fn rumpuser_mutex_exit "struct rumpuser_mtx *mtx"
642.Pp
643.Ft void
644.Fn rumpuser_mutex_destroy "struct rumpuser_mtx *mtx"
645.Pp
646.Ft void
647.Fn rumpuser_mutex_owner "struct rumpuser_mtx *mtx" "struct lwp **lp"
648.Pp
649Mutexes provide mutually exclusive locking.
650The flags, of which at least one must be given, are as follows:
651.Bl -tag -width "XRUMPUSER_MTX_KMUTEX"
652.It Dv RUMPUSER_MTX_SPIN
653Create a spin mutex.
654Locking this type of mutex must not relinquish rump kernel context
655even when
656.Fn rumpuser_mutex_enter
657is used.
658.It Dv RUMPUSER_MTX_KMUTEX
659The mutex must track and be able to return the rump kernel thread
660that owns the mutex (if any).
661If this flag is not specified,
662.Fn rumpuser_mutex_owner
663will never be called for that particular mutex.
664.El
665.Pp
666.Ft void
667.Fn rumpuser_rw_init "struct rumpuser_rw **rwp"
668.Pp
669.Ft void
670.Fn rumpuser_rw_enter "int enum_rumprwlock" "struct rumpuser_rw *rw"
671.Pp
672.Ft int
673.Fn rumpuser_rw_tryenter "int enum_rumprwlock" "struct rumpuser_rw *rw"
674.Pp
675.Ft int
676.Fn rumpuser_rw_tryupgrade "struct rumpuser_rw *rw"
677.Pp
678.Ft void
679.Fn rumpuser_rw_downgrade "struct rumpuser_rw *rw"
680.Pp
681.Ft void
682.Fn rumpuser_rw_exit "struct rumpuser_rw *rw"
683.Pp
684.Ft void
685.Fn rumpuser_rw_destroy "struct rumpuser_rw *rw"
686.Pp
687.Ft void
688.Fo rumpuser_rw_held
689.Fa "int enum_rumprwlock" "struct rumpuser_rw *rw" "int *heldp"
690.Fc
691.Pp
692Read/write locks provide either shared or exclusive locking.
693The possible values for
694.Fa lk
695are
696.Dv RUMPUSER_RW_READER
697and
698.Dv RUMPUSER_RW_WRITER .
699Upgrading means trying to migrate from an already owned shared
700lock to an exclusive lock and downgrading means migrating from
701an already owned exclusive lock to a shared lock.
702.Pp
703.Ft void
704.Fn rumpuser_cv_init "struct rumpuser_cv **cvp"
705.Pp
706.Ft void
707.Fn rumpuser_cv_destroy "struct rumpuser_cv *cv"
708.Pp
709.Ft void
710.Fn rumpuser_cv_wait "struct rumpuser_cv *cv" "struct rumpuser_mtx *mtx"
711.Pp
712.Ft void
713.Fn rumpuser_cv_wait_nowrap "struct rumpuser_cv *cv" "struct rumpuser_mtx *mtx"
714.Pp
715.Ft int
716.Fo rumpuser_cv_timedwait
717.Fa "struct rumpuser_cv *cv" "struct rumpuser_mtx *mtx"
718.Fa "int64_t sec" "int64_t nsec"
719.Fc
720.Pp
721.Ft void
722.Fn rumpuser_cv_signal "struct rumpuser_cv *cv"
723.Pp
724.Ft void
725.Fn rumpuser_cv_broadcast "struct rumpuser_cv *cv"
726.Pp
727.Ft void
728.Fn rumpuser_cv_has_waiters "struct rumpuser_cv *cv" "int *waitersp"
729.Pp
730Condition variables wait for an event.
731The
732.Fa mtx
733interlock eliminates a race between checking the predicate and
734sleeping on the condition variable; the mutex should be released
735for the duration of the sleep in the normal atomic manner.
736The timedwait variant takes a specifier indicating a relative
737sleep duration after which the routine will return with
738.Er ETIMEDOUT .
739If a timedwait is signaled before the timeout expires, the
740routine will return 0.
741.Pp
742The order in which the hypervisor
743reacquires the rump kernel context and interlock mutex before
744returning into the rump kernel is as follows.
745In case the interlock mutex was initialized with both
746.Dv RUMPUSER_MTX_SPIN
747and
748.Dv RUMPUSER_MTX_KMUTEX ,
749the rump kernel context is scheduled before the mutex is reacquired.
750In case of a purely
751.Dv RUMPUSER_MTX_SPIN
752mutex, the mutex is acquired first.
753In the final case the order is implementation-defined.
754.Sh RETURN VALUES
755All routines which return an integer return an errno value.
756The hypervisor must translate the value to the native errno
757namespace used by the rump kernel.
758Routines which do not return an integer may never fail.
759.Sh SEE ALSO
760.Xr rump 3
761.Rs
762.%A Antti Kantee
763.%D 2012
764.%J Aalto University Doctoral Dissertations
765.%T Flexible Operating System Internals: The Design and Implementation of the Anykernel and Rump Kernels
766.%O Section 2.3.2: The Hypercall Interface
767.Re
768.Pp
769For a list of all known implementations of the
770.Nm
771interface, see
772.Lk https://github.com/rumpkernel/wiki/wiki/Platforms .
773.Sh HISTORY
774The rump kernel hypercall API was first introduced in
775.Nx 5.0 .
776The API described above first appeared in
777.Nx 7.0 .
778