---
name: "gensio_os_funcs_wait_intr_sigmask"
section: "3"
platform: "linux"
package: "gensio"
version: "3.0.4-1"
release: "Arch Linux 2026-11-01"
platforms: ["linux"]
url: "https://new.carta.tech/gensio_os_funcs"
---

# gensio\_os\_funcs\_wait\_intr\_sigmask(3)

Abstraction for some operating system functions used by the gensio library

Part of [gensio\_os\_funcs(3)](/gensio_os_funcs/3.md).

## NAME

gensio\_os\_funcs - Abstraction for some operating system functions used by the gensio library

## SYNOPSIS

**#include \<gensio/gensio\_os\_funcs\_public.h\>**

**struct gensio\_os\_funcs {}**

**int gensio\_default\_os\_hnd(int wake\_sig, struct gensio\_os\_funcs \*\*o)**

**int gensio\_alloc\_os\_funcs(int wake\_sig, struct gensio\_os\_funcs \*\*o,**\
\
                 unsigned int flags, ...)

**int gensio\_unix\_funcs\_alloc(struct selector\_s \*sel, int wake\_sig,**\
\
 		struct gensio\_os\_funcs \*\*o)

**int gensio\_win\_funcs\_alloc(struct gensio\_os\_funcs \*\*o)**

**void gensio\_os\_funcs\_free(struct gensio\_os\_funcs \*o);**

**int gensio\_os\_proc\_setup(struct gensio\_os\_funcs \*o,**\
\
 			 struct gensio\_os\_proc\_data \*\*data)

**void gensio\_os\_proc\_cleanup(struct gensio\_os\_proc\_data \*data);**

**int gensio\_os\_thread\_setup(struct gensio\_os\_funcs \*o);**

**sigset\_t \*gensio\_os\_proc\_unix\_get\_wait\_sigset(**\
\
                          struct gensio\_os\_proc\_data \*data);

**int gensio\_os\_new\_thread(struct gensio\_os\_funcs \*o,**\
\
 			 void (\*start\_func)(void \*data), void \*data,\
\
 			 struct gensio\_thread \*\*thread\_id);

**int gensio\_os\_wait\_thread(struct gensio\_thread \*thread\_id);**

**int gensio\_os\_proc\_register\_term\_handler(struct gensio\_os\_proc\_data \*data,**\
\
 					 void (\*handler)(void \*handler\_data),\
\
 					 void \*handler\_data);

**int gensio\_os\_proc\_register\_reload\_handler(struct gensio\_os\_proc\_data \*data,**\
\
 					   void (\*handler)(void \*handler\_data),\
\
 					   void \*handler\_data);

**int gensio\_os\_proc\_register\_winsize\_handler(struct gensio\_os\_proc\_data \*data,**\
\
 					struct gensio\_iod \*console\_iod,\
\
 					void (\*handler)(int x\_chrs, int y\_chrs,\
\
 							int x\_bits, int y\_bits,\
\
 							void \*handler\_data),\
\
 					void \*handler\_data);

**void \*gensio\_os\_funcs\_zalloc(struct gensio\_os\_funcs \*o, gensiods len);**

**void gensio\_os\_funcs\_zfree(struct gensio\_os\_funcs \*o, void \*data);**

**struct gensio\_lock \*gensio\_os\_funcs\_alloc\_lock(struct gensio\_os\_funcs \*o);**

**void gensio\_os\_funcs\_free\_lock(struct gensio\_os\_funcs \*o,**\
\
 			       struct gensio\_lock \*lock);

**void gensio\_os\_funcs\_lock(struct gensio\_os\_funcs \*o,**\
\
 			  struct gensio\_lock \*lock);

**void gensio\_os\_funcs\_unlock(struct gensio\_os\_funcs \*o,**\
\
 			    struct gensio\_lock \*lock);

**void gensio\_os\_funcs\_get\_monotonic\_time(struct gensio\_os\_funcs \*o,**\
\
 					gensio\_time \*time);

**struct gensio\_timer \*gensio\_os\_funcs\_alloc\_timer(struct gensio\_os\_funcs \*o,**\
\
 				    void (\*handler)(struct gensio\_timer \*t,\
\
 						    void \*cb\_data),\
\
 				    void \*cb\_data);

**void gensio\_os\_funcs\_free\_timer(struct gensio\_os\_funcs \*o,**\
\
 				struct gensio\_timer \*timer);

**int gensio\_os\_funcs\_start\_timer(struct gensio\_os\_funcs \*o,**\
\
 				struct gensio\_timer \*timer,\
\
 				gensio\_time \*timeout);

**int gensio\_os\_funcs\_start\_timer\_abs(struct gensio\_os\_funcs \*o,**\
\
 				    struct gensio\_timer \*timer,\
\
 				    gensio\_time \*timeout);

**int gensio\_os\_funcs\_stop\_timer(struct gensio\_os\_funcs \*o,**\
\
 			       struct gensio\_timer \*timer);

**int gensio\_os\_funcs\_stop\_timer\_with\_done(struct gensio\_os\_funcs \*o,**\
\
 			    struct gensio\_timer \*timer,\
\
 			    void (\*done\_handler)(struct gensio\_timer \*t,\
\
 						 void \*cb\_data),\
\
 			    void \*cb\_data);

**struct gensio\_runner \*gensio\_os\_funcs\_alloc\_runner(struct gensio\_os\_funcs \*o,**\
\
 				      void (\*handler)(struct gensio\_runner \*r,\
\
 						      void \*cb\_data),\
\
 				      void \*cb\_data);

**void gensio\_os\_funcs\_free\_runner(struct gensio\_os\_funcs \*o,**\
\
 				 struct gensio\_runner \*runner);

**int gensio\_os\_funcs\_run(struct gensio\_os\_funcs \*o,**\
\
 			struct gensio\_runner \*runner);

**typedef void (gensio\_vlog\_func)(struct gensio\_os\_funcs \*o,**\
\
 				enum gensio\_log\_levels level,\
\
 				const char \*log, va\_list args);\

**void gensio\_os\_funcs\_set\_vlog(struct gensio\_os\_funcs \*o,**\
                               gensio\_vlog\_func func);

**int gensio\_os\_funcs\_service(struct gensio\_os\_funcs \*o, gensio\_time \*timeout);**

**int gensio\_os\_funcs\_handle\_fork(struct gensio\_os\_funcs \*o);**

**struct gensio\_waiter \*gensio\_os\_funcs\_alloc\_waiter(struct gensio\_os\_funcs \*o);**

**void gensio\_os\_funcs\_free\_waiter(struct gensio\_os\_funcs \*o,**\
\
 				 struct gensio\_waiter \*waiter);

**int gensio\_os\_funcs\_wait(struct gensio\_os\_funcs \*o,**\
\
 			 struct gensio\_waiter \*waiter, unsigned int count,\
\
 			 gensio\_time \*timeout);

**int gensio\_os\_funcs\_wait\_intr(struct gensio\_os\_funcs \*o,**\
\
 			      struct gensio\_waiter \*waiter, unsigned int count,\
\
 			      gensio\_time \*timeout);

**int gensio\_os\_funcs\_wait\_intr\_sigmask(struct gensio\_os\_funcs \*o,**\
\
 				      struct gensio\_waiter \*waiter,\
\
 				      unsigned int count,\
\
 				      gensio\_time \*timeout,\
\
 				      struct gensio\_os\_proc\_data \*proc\_data);

**void gensio\_os\_funcs\_wake(struct gensio\_os\_funcs \*o,**\
\
 			  struct gensio\_waiter \*waiter);

**void gensio\_os\_funcs\_set\_data(struct gensio\_os\_funcs \*o, void \*data);**

**void \*gensio\_os\_funcs\_get\_data(struct gensio\_os\_funcs \*o);**

## DESCRIPTION

This structure provides an abstraction for the gensio library that lets it work with various event libraries.  It provides the following basic functions:

- memory allocation - Allocate and free memory.

  - mutexes - Provide mutual exclusion.

  - file handler callbacks - Allows file descriptors to be monitored

  and report when I/O is ready on them.

- timers - Call callbacks after a certain amount of time has elapsed.

  - runners - Run a function in a new execution context. Calling callbacks

  straight from user functions can result in deadlocks, this provides a way to call callbacks from a separate context.

- waiters - Wait for operations to occur while running timers, runners

  and watching for file descriptors.

- logging - Allow the gensio library to generate logs to report issues.

  This document describes the public functions that users can use.  An os handler has many other functions for use by gensios, these are documented in the os funcs include file.

The basic issue is that there are various event handling libraries (Tcl/Tk, glib, Xlib, custom ones, etc.) and you may want to integrate the gensio library with one of these.  Even though it's a bit of a pain to have to pass one of these around, it adds needed flexibility.

**gensio\_default\_os\_hnd (Deprecated)** provides a way to get the default OS function handler for the platform.  The same value will be returned each time, only one is created.  You should generally use this one unless you have a special need as documented above.  Use of this is now discouraged in general. Having two independent parts of a system share an OS funcs without knowing about it is likely to lead to issues.  If a program knows it is the only thing using it, then this is ok for now, but it's going to be deprecated at some point.

**gensio\_alloc\_os\_funcs** allocates a new OS function handler for the platform, for Unix or Windows.  Multiple OS handlers can be used to handle different I/O at different priorities.  When you create a gensio, all I/O callbacks will be handled from the OS handler used to create it.  So you can run different OS handlers in threads of different priority to run different gensios at different priority.  Otherwise there is not much reason for more than one of these.

The *wake\_sig* parameter usage on Windows is unused.  For Unix systems, this signal is used to signal other processes that may be waiting that they need to wake up.  This is used to wake up a process waiting on a waiter, and it's used to signal all waiting processes if a timer is added that is sooner than any other timer so they can adjust their waits.

If you are running your program in a single thread, you can safely pass zero into this parameter.  If you pass in anything but zero, it will set up that signal by removing it from the sigmask and installing a handler for it.

If your app is multi-threaded (or, more accurately, if your app has multiple threads that are making gensio calls) you must pass a valid signal into this, and you must set up an empty handler for this signal, and the signal must be blocked in all threads that call a wait function.  You should not use this signal for anything else.  The function that allocates a signal handler will block the signal in the calling thread, and that sigmask is passed on to other threads it creates.  But if you have allocated threads before allocating the os funcs, you must make sure those other threads have this signal blocked.

You can pass in GENSIO\_OS\_FUNCS\_DEFAULT\_THREAD\_SIGNAL to take the default signal handler, which is SIGUSR1.

On unix, **gensio\_os\_proc\_setup** function handles all the above mentioned signal setup for you (blocking signals, setting signal handler), for the wake signal as above and also for some other signals like SIGTERM, SIGCHILD, SIGPIPE, and others.  You should generally use that unless you have special needs.  It also does necessary setup on Windows.

Also, if you pass in a different value to **gensio\_default\_os\_hnd** than the first one you passed in, it will return *GE\_INVAL.* You can pass in different values to **gensio\_unix\_funcs\_alloc** calls, and it will use them, but there's not much value in this.  The os funcs for Unix can share a signal handler.  And there's not much value is multiple OS funcs, anyway.

**gensio\_os\_thread\_setup** is much like gensio\_os\_proc\_setup, but it only sets up the signal handlers and blocking signals for the wakeup signal, it doesn't do any of the other setup.  It allows you to bring a thread in to gensio that wasn't created by gensio.  It also does some necessary setup on Windows for the thread.  If you have no signal handling needs, you can generally use this instead of **gensio\_os\_proc\_setup().** If you have signal handling needs, one thread should call **gensio\_os\_proc\_setup()** and all other threads should call this function if they were not created by gensio.

**gensio\_unix\_funcs\_alloc** and **gensio\_win\_funcs\_alloc** allocate the normal os funcs for Unix and Windows based systems, respectively.

The *sel* parameter for Unix allows you to create your own selector object and pass it to the OS handler.  Passing in NULL will cause it to allocate it's own selector object.  See the selector.h include file for details.

The *wake\_sig* value is a signal for use by the OS functions for internal communication between threads.  If you are running a multi-threaded application, you must provide a valid signal that you don't use for any other purpose, generally **SIGUSR1** or **SIGUSR2.** You can use **GENSIO\_DEF\_WAKE\_SIG** which is zero on Windows and **SIGUSR1** on Unix.

The *gensio\_os\_proc\_setup* function does all the standard setup for a process.  You should almost certainly use this function.  On Windows this sets up some basic things so termination registering will work, but on Unix it does all the signal handling setup, so you don't have to do all the things mentioned above.  This will block SIGPIPE (because those come in when connections die and most applications don't care), SIGCHLD (those come in for stdio and pty gensios), and the *wake\_sig* if that is set.  It also install signal handlers for SIGCHLD and the *wake\_sig* (if set) and sets up a signal mask.

For Unix this is generally what you want, you don't want SIGPIPE doing bad things and having SIGCHLD wake up a wait can speed things up a bit when waiting for subprograms.

If you use the *gensio\_os\_funcs\_wait\_intr\_sigmask* OS function, you must pass the proc\_data value returned by *gensio\_os\_proc\_setup* into that.  If you want to modify the wait signal mask, you can use *gensio\_os\_proc\_unix\_get\_wait\_sigset* to fetch a pointer to it and modify it.

Note that if you call this more than once without calling *gensio\_os\_proc\_cleanup* in between, it will return *GE\_INUSE.*

The *gensio\_os\_proc\_cleanup* function undoes all the changes *gensio\_os\_proc\_setup* does, along with unregistering any signal handlers done by register calls.  On Unix it restores the signal mask and signal handlers it sets to their previous values.  On Windows it remove registered handlers.

The *gensio\_os\_new\_thread* function starts a new thread at **start\_func** passing in the given data value.  It returns a **thread\_id** that you must pass into the wait function.  This is just basic generic threads, you can use your OS functions if you need more control over the threads.  If you use threads, make sure to see the notes above about setting up for them properly.  This must be called from a thread that is already set up.

The *gensio\_os\_wait\_thread* waits for a thread to stop.  Note that it does not cause the thread to stop, it waits for it to stop.  You have to cause the thread to stop yourself.

The *gensio\_os\_proc\_register\_term\_handler* function passes a handler to call when a termination (SIGINT, SIGQUIT, SIGTERM on Unix, console control handler or WM\_CLOSE on windows) is received by the process.  Set **handler** to **NULL** to disable.  If you do this on Unix, the signals will be blocked except when in a wait or service call.  Call this before starting any other threads so they inherit the proper sigmask.

The *gensio\_os\_proc\_register\_reload\_handler* sets the function to call when a reload is requested by the operating system (SIGHUP on Unix). Set **handler** to **NULL** to disable.  On Unix, this will cause SIGHUP to be blocked except when in a wait or service call.  Call this before starting any other threads so they inherit the proper sigmask.

The *gensio\_os\_proc\_register\_winsize\_handler* function sets the function to call when a console window size change is requested by the operating system (SIGWINCH on Unix, through the console interface on Windows).  It will supply the new size parameters.  Set **handler** and **console\_iod** to **NULL** to disable.  Note that the handler will be called with current window size parameters after this is called.  This may be called after threads are started, the SIGWINCH signal mask is set up by default in gensio\_os\_proc\_setup on \*nix systems.

**gensio\_os\_funcs\_zalloc** allocates a block of memory and zeroes it.  The **gensio** library has it's own allocator/deallocator that is using in testing to track if all allocated data is freed when the tests shut down, and to catch memory overruns, underruns, and use after free errors.  Returns **NULL** if the memory cannot be allocated.  Use **gensio\_os\_funcs\_zfree** to free the allocated memory.

**gensio\_os\_funcs\_alloc\_lock** allocates a mutex that can be used for locking by the user.  Use **gensio\_os\_funcs\_lock** and **gensio\_os\_funcs\_unlock** to lock/unlock the mutex.  The **gensio\_os\_funcs\_free\_lock** will make sure the lock is not locked and free the data associated with the lock.  Note that even for os funcs that don't implement locks, this will implement a counter to make sure that all locks are balanced.

**gensio\_os\_funcs\_get\_monotonic\_time** returns a time value from the monotonic clock used for **gensio\_os\_start\_timer\_abs.** It can also be used as a standard monotonic clock, but is not a wall clock of any kind.

**gensio\_os\_funcs\_set\_vlog** *must* be called by the user to set a log handling function for the os funcs. If something goes wrong internally in the gensio library, this log function will be called to report the issue.

Timers are allocated with **gensio\_os\_funcs\_alloc\_timer.** When the timer expires, the **handlers** will be called with the given **cb\_data.** This will return **NULL** if the timer cannot be allocated.  Timers are not running when allocated, the must be started with **gensio\_os\_funcs\_start\_timer,** or **gensio\_os\_funcs\_start\_timer\_abs.** The first starts a timer relative to the current time.  The second starts a timer based upon a monotonic clock, see **gensio\_os\_funcs\_get\_monotonic\_time** for details.  These will return **GE\_INUSE** if the timer was already running.  To stop a timer, call either **gensio\_os\_funcs\_stop\_timer** or **gensio\_os\_funcs\_stop\_timer\_with\_done.** These both return **GE\_TIMEDOUT** if the timer is not running.  The first has no way to assure that the timer is finished running its handlers; the timer handler may still be active when it returns.  If it does not return an error, the second will call the **done\_handler** function when the timer is completely stopped and all the handlers are finished.  The second also returns **GE\_INUSE** if the timer has already been stopped but the done handler hasn't been called yet.  Note that you cannot start the timer again until the done handler is called.  And finally, to free a timer, use **gensio\_os\_funcs\_free\_timer.** The timer should not be running when calling this.

Runners are sort of like zero-time timers, they will just be called immediately.  They are useful for escaping from deep locking situations where you want to do something at the base context.  Use **gensio\_os\_funcs\_alloc\_runner** to allocate one of these.  It returns **NULL** if the runner cannot be allocated. **gensio\_os\_funcs\_run** causes the handler to be called.  It returns **GE\_INUSE** if the runner is currently already scheduled to be run.  And **gensio\_os\_funcs\_free\_runner** frees the runner.  It should not be currently scheduled to run.

**gensio\_os\_funcs\_service** provides the main service function to run timers, runners, I/O handling, etc.  If it is interrupted by a signal (on Unix), it returns **GE\_INTERRUPTED.** If **timeout** is non-NULL, it is a relative amount of time to wait and this will return **GE\_TIMEDOUT** if the timeout expires.  Note that for long timeouts (days) this may return early on some os funcs, so don't rely on this for timing.  When this returns, the timeout will be updated to any remaining time, even on an early timeout.  Generally you don't use this function, you use waiters instead.

Call **gensio\_os\_funcs\_handle\_fork** in the child function after a fork (Unix only).  This cleans up various things and readies the gensio library to be used after a fork. If this returns an error, it is likely that the gensio library is unusable on the child.

Waiters are used to wait for things to happen.  When the thing happens occurs, that code should call wake to wake the waiter.  Normal servicing of tiers, runners, I/O, etc. are done while waiting. Waiters and wakes are count based, if you call the wake before the wait that's ok, the wake will be waiting when the wait happens.  If you call wake 3 times, there are 3 wakes pending.  To allocate a waiter, call **gensio\_os\_funcs\_alloc\_waiter.** It returns NULL if it cannot allocate the waiter. **gensio\_os\_funcs\_wait** waits for **count** wakeups to be done and then returns zero.  If **timeout** is **NULL** it waits forever.  Otherwise if the timeout expires it returns **GE\_TIMEDOUT** and the timeout is updated to the remaining time.  If this times out, no wakeups are "used" by the function, if only some are pending those are still pending. **gensio\_os\_funcs\_wait\_intr** is like **gensio\_os\_funcs\_wait** except if an signal is received (Unix only) it will return **GE\_INTERRUPTED.** **gensio\_os\_funcs\_wait\_intr\_sigmask** is like **gensio\_os\_funcs\_wait\_intr** but allows a user-specified signal mask to be installed (Unix only).  See **gensio\_os\_proc\_setup** for details.  To send a single wakeup to a waiter, use **gensio\_os\_funcs\_wake.** And, of course, call **gensio\_os\_funcs\_free\_waiter** to free a waiter.

An os funcs has a single void pointer that the user may install some data in for their own use.  Use **gensio\_os\_funcs\_set\_data** to set this data and **gensio\_os\_funcs\_get\_data** to retrieve it.

## RETURN VALUES

Return values are documented in the text above.

## SEE ALSO

[gensio\_set\_log\_mask(3)](/gensio_set_log_mask/3.md), [gensio\_get\_log\_mask(3)](/gensio_get_log_mask/3.md), [gensio\_log\_level\_to\_str(3)](/gensio_log_level_to_str/3.md), [gensio(5)](/gensio/5.md), [gensio\_err(3)](/gensio_err/3.md)
