diff --git a/include/gensio/gensio_os_funcs_public.h b/include/gensio/gensio_os_funcs_public.h index 8ea076d7..6b14ea04 100644 --- a/include/gensio/gensio_os_funcs_public.h +++ b/include/gensio/gensio_os_funcs_public.h @@ -19,6 +19,9 @@ extern "C" { GENSIOOSH_DLL_PUBLIC int gensio_default_os_hnd(int wake_sig, struct gensio_os_funcs **o); +GENSIOOSH_DLL_PUBLIC +int gensio_alloc_os_hnd(int wake_sig, struct gensio_os_funcs **o); + GENSIOOSH_DLL_PUBLIC int gensio_os_proc_setup(struct gensio_os_funcs *o, struct gensio_os_proc_data **data); diff --git a/lib/gensio_unix.c b/lib/gensio_unix.c index 60f5e1bb..53c81d2e 100644 --- a/lib/gensio_unix.c +++ b/lib/gensio_unix.c @@ -950,6 +950,7 @@ gensio_unix_get_wake_sig(struct gensio_os_funcs *f) static lock_type defos_lock = LOCK_INITIALIZER; static struct gensio_os_funcs *defoshnd; static int defoshnd_wake_sig = -1; +static bool proc_setup; static struct gensio_os_funcs * gensio_unix_get_funcs(struct gensio_os_funcs *f) @@ -1758,7 +1759,11 @@ gensio_os_proc_setup(struct gensio_os_funcs *o, struct gensio_os_proc_data *data; sigset_t sigs; struct sigaction sigdo; - int rv; + int rv = GE_INUSE; + + LOCK(&defos_lock); + if (proc_setup) + goto out; data = &proc_data; data->o = o; @@ -1781,7 +1786,7 @@ gensio_os_proc_setup(struct gensio_os_funcs *o, rv = sigprocmask(SIG_BLOCK, &sigs, &data->old_sigs); if (rv) { rv = gensio_os_err_to_err(o, errno); - return rv; + goto out; } data->wait_sigs = data->old_sigs; if (data->wake_sig) @@ -1800,7 +1805,7 @@ gensio_os_proc_setup(struct gensio_os_funcs *o, if (rv) { rv = gensio_os_err_to_err(o, errno); sigprocmask(SIG_SETMASK, &data->old_sigs, NULL); - return rv; + goto out; } if (data->wake_sig) { @@ -1811,7 +1816,7 @@ gensio_os_proc_setup(struct gensio_os_funcs *o, rv = gensio_os_err_to_err(o, errno); sigaction(SIGCHLD, &data->old_sigchld, NULL); sigprocmask(SIG_SETMASK, &data->old_sigs, NULL); - return rv; + goto out; } } @@ -1821,13 +1826,16 @@ gensio_os_proc_setup(struct gensio_os_funcs *o, sigprocmask(SIG_SETMASK, &data->old_sigs, NULL); if (data->wake_sig) sigaction(data->wake_sig, &data->old_wakesig, NULL); - return rv; + goto out; } LOCK_INIT(&data->handler_lock); *rdata = data; - return 0; + proc_setup = true; + out: + UNLOCK(&defos_lock); + return rv; } void @@ -1877,6 +1885,12 @@ check_for_sigpending(sigset_t *check_for) void gensio_os_proc_cleanup(struct gensio_os_proc_data *data) { + LOCK(&defos_lock); + if (!proc_setup) + goto out; + + proc_setup = false; + /* We should be single-threaded here. */ while (data->cleanup_handlers) { struct gensio_os_cleanup_handler *h = data->cleanup_handlers; @@ -1912,6 +1926,9 @@ gensio_os_proc_cleanup(struct gensio_os_proc_data *data) ; sigprocmask(SIG_SETMASK, &data->old_sigs, NULL); + out: + UNLOCK(&defos_lock); + return; } void @@ -2359,6 +2376,15 @@ gensio_default_os_hnd(int wake_sig, struct gensio_os_funcs **o) return err; } +int +gensio_alloc_os_hnd(int wake_sig, struct gensio_os_funcs **o) +{ + if (wake_sig == -198234) + wake_sig = SIGUSR1; + + return gensio_unix_funcs_alloc(NULL, wake_sig, o); +} + void gensio_osfunc_exit(int rv) { diff --git a/lib/gensio_win.c b/lib/gensio_win.c index 4e404aa5..68714e39 100644 --- a/lib/gensio_win.c +++ b/lib/gensio_win.c @@ -3935,28 +3935,36 @@ struct gensio_os_proc_data { struct gensio_os_cleanup_handler *cleanup_handlers; }; static struct gensio_os_proc_data proc_data; +bool proc_setup; int gensio_os_proc_setup(struct gensio_os_funcs *o, struct gensio_os_proc_data **data) { - int rv; + int rv = GE_INUSE; HRESULT res; + AcquireSRWLockExclusive(&def_win_os_funcs_lock); + if (proc_setup) + goto out; + + rv = 0; res = CoInitializeEx(NULL, COINIT_MULTITHREADED); switch (res) { - case S_OK: case S_FALSE: - break; - case RPC_E_CHANGED_MODE: return GE_INCONSISTENT; - case E_INVALIDARG: return GE_INVAL; - case E_OUTOFMEMORY: return GE_NOMEM; - case E_UNEXPECTED: default: return GE_OSERR; + case S_OK: case S_FALSE: break; + case RPC_E_CHANGED_MODE: rv = GE_INCONSISTENT; break; + case E_INVALIDARG: rv = GE_INVAL; break; + case E_OUTOFMEMORY: rv = GE_NOMEM; break; + case E_UNEXPECTED: default: rv = GE_OSERR; break; } + if (rv) + goto out; proc_data.global_waiter = CreateSemaphoreA(NULL, 0, 1000000, NULL); if (!proc_data.global_waiter) { CoUninitialize(); - return GE_NOMEM; + rv = GE_NOMEM; + goto out; } rv = o->control(o, GENSIO_CONTROL_SET_PROC_DATA, &proc_data, NULL); @@ -3964,12 +3972,14 @@ gensio_os_proc_setup(struct gensio_os_funcs *o, CloseHandle(proc_data.global_waiter); CoUninitialize(); proc_data.global_waiter = NULL; - return rv; + goto out; } LOCK_INIT(&proc_data.lock); proc_data.o = o; *data = &proc_data; - return 0; + out: + ReleaseSRWLockExclusive(&def_win_os_funcs_lock); + return rv; } static void @@ -4053,6 +4063,11 @@ gensio_register_os_cleanup_handler(struct gensio_os_funcs *o, void gensio_os_proc_cleanup(struct gensio_os_proc_data *data) { + AcquireSRWLockExclusive(&def_win_os_funcs_lock); + if (!proc_setup) + goto out; + + proc_setup = false; /* We should be single-threaded here. */ while (data->cleanup_handlers) { struct gensio_os_cleanup_handler *h = data->cleanup_handlers; @@ -4075,6 +4090,8 @@ gensio_os_proc_cleanup(struct gensio_os_proc_data *data) } LOCK_DESTROY(&proc_data.lock); CoUninitialize(); + out: + ReleaseSRWLockExclusive(&def_win_os_funcs_lock); } HANDLE @@ -4283,6 +4300,12 @@ gensio_default_os_hnd(int wake_sig, struct gensio_os_funcs **o) return 0; } +int +gensio_alloc_os_hnd(int wake_sig, struct gensio_os_funcs **o) +{ + return gensio_win_funcs_alloc(o); +} + void gensio_osfunc_exit(int rv) { diff --git a/man/gensio_os_funcs.3 b/man/gensio_os_funcs.3 index f9d82d38..cd8392ae 100644 --- a/man/gensio_os_funcs.3 +++ b/man/gensio_os_funcs.3 @@ -9,6 +9,8 @@ by the gensio library .PP .B int gensio_default_os_hnd(int wake_sig, struct gensio_os_funcs **o) .PP +.B int gensio_alloc_os_hnd(int wake_sig, struct gensio_os_funcs **o) +.PP .B int gensio_unix_funcs_alloc(struct selector_s *sel, int wake_sig, .br struct gensio_os_funcs **o) @@ -218,11 +220,20 @@ 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. .B gensio_default_os_hnd -provides a way to allocate a default OS function handler for the +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. +.B gensio_alloc_os_hnd +allocates a new OS 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 to do this. + The .I wait_sig parameter usage on Windows is unused. For Unix systems, this signal @@ -308,6 +319,11 @@ into that. If you want to modify the wait signal mask, you can use .I 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 +.I gensio_os_proc_cleanup +inbetween, it will return +.I GE_INUSE. + The .I gensio_os_proc_cleanup function undoes all the changes