From a72f3b87bcdb8b8f14877d2ce9c68a09661f54c3 Mon Sep 17 00:00:00 2001 From: Jiri Svoboda Date: Fri, 18 Oct 2024 01:20:09 +0200 Subject: [PATCH] System protocol library, incl. unit tests --- abi/include/abi/ipc/interfaces.h | 6 +- uspace/lib/meson.build | 1 + uspace/lib/system/doc/doxygroups.h | 3 + uspace/lib/system/include/ipc/system.h | 53 ++++ uspace/lib/system/include/system.h | 50 ++++ uspace/lib/system/include/system_srv.h | 62 +++++ uspace/lib/system/include/types/system.h | 52 ++++ uspace/lib/system/meson.build | 37 +++ uspace/lib/system/private/system.h | 60 +++++ uspace/lib/system/src/system.c | 228 ++++++++++++++++ uspace/lib/system/src/system_srv.c | 142 ++++++++++ uspace/lib/system/test/main.c | 35 +++ uspace/lib/system/test/system.c | 316 +++++++++++++++++++++++ 13 files changed, 1044 insertions(+), 1 deletion(-) create mode 100644 uspace/lib/system/doc/doxygroups.h create mode 100644 uspace/lib/system/include/ipc/system.h create mode 100644 uspace/lib/system/include/system.h create mode 100644 uspace/lib/system/include/system_srv.h create mode 100644 uspace/lib/system/include/types/system.h create mode 100644 uspace/lib/system/meson.build create mode 100644 uspace/lib/system/private/system.h create mode 100644 uspace/lib/system/src/system.c create mode 100644 uspace/lib/system/src/system_srv.c create mode 100644 uspace/lib/system/test/main.c create mode 100644 uspace/lib/system/test/system.c diff --git a/abi/include/abi/ipc/interfaces.h b/abi/include/abi/ipc/interfaces.h index 54f05d19da..fb72d49da4 100644 --- a/abi/include/abi/ipc/interfaces.h +++ b/abi/include/abi/ipc/interfaces.h @@ -201,7 +201,11 @@ typedef enum { INTERFACE_WNDMGT_CB = FOURCC_COMPACT('w', 'm', 'g', 't') | IFACE_EXCHANGE_SERIALIZE | IFACE_MOD_CALLBACK, INTERFACE_TBARCFG_NOTIFY = - FOURCC_COMPACT('t', 'b', 'c', 'f') | IFACE_EXCHANGE_SERIALIZE + FOURCC_COMPACT('t', 'b', 'c', 'f') | IFACE_EXCHANGE_SERIALIZE, + INTERFACE_SYSTEM = + FOURCC_COMPACT('s', 's', 't', 'm') | IFACE_EXCHANGE_SERIALIZE, + INTERFACE_SYSTEM_CB = + FOURCC_COMPACT('s', 's', 't', 'm') | IFACE_EXCHANGE_SERIALIZE | IFACE_MOD_CALLBACK } iface_t; #endif diff --git a/uspace/lib/meson.build b/uspace/lib/meson.build index 9305309bad..0433bf9089 100644 --- a/uspace/lib/meson.build +++ b/uspace/lib/meson.build @@ -89,6 +89,7 @@ libs = [ 'riff', 'scsi', 'sif', + 'system', 'tbarcfg', 'termui', 'trackmod', diff --git a/uspace/lib/system/doc/doxygroups.h b/uspace/lib/system/doc/doxygroups.h new file mode 100644 index 0000000000..7c62f8e58c --- /dev/null +++ b/uspace/lib/system/doc/doxygroups.h @@ -0,0 +1,3 @@ +/** @addtogroup libsystem libsystem + * @ingroup libs + */ diff --git a/uspace/lib/system/include/ipc/system.h b/uspace/lib/system/include/ipc/system.h new file mode 100644 index 0000000000..6936070c43 --- /dev/null +++ b/uspace/lib/system/include/ipc/system.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024 Jiri Svoboda + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @addtogroup libsystem + * @{ + */ +/** @file System control service interface + */ + +#ifndef _LIBSYSTEM_IPC_SYSTEM_H_ +#define _LIBSYSTEM_IPC_SYSTEM_H_ + +#include + +typedef enum { + SYSTEM_SHUTDOWN_COMPLETE = IPC_FIRST_USER_METHOD, + SYSTEM_SHUTDOWN_FAILED +} system_event_t; + +typedef enum { + SYSTEM_CALLBACK_CREATE = IPC_FIRST_USER_METHOD, + SYSTEM_SHUTDOWN +} system_request_t; + +#endif + +/** @} + */ diff --git a/uspace/lib/system/include/system.h b/uspace/lib/system/include/system.h new file mode 100644 index 0000000000..1bc9186fa4 --- /dev/null +++ b/uspace/lib/system/include/system.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024 Jiri Svoboda + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @addtogroup libsystem + * @{ + */ +/** @file System control service interface + */ + +#ifndef _LIBSYSTEM_SYSTEM_H_ +#define _LIBSYSTEM_SYSTEM_H_ + +#include +#include "types/system.h" + +#define SYSTEM_DEFAULT "system" + +extern errno_t system_open(const char *, system_cb_t *, void *, system_t **); +extern void system_close(system_t *); +extern errno_t system_shutdown(system_t *); + +#endif + +/** @} + */ diff --git a/uspace/lib/system/include/system_srv.h b/uspace/lib/system/include/system_srv.h new file mode 100644 index 0000000000..db6f027b3f --- /dev/null +++ b/uspace/lib/system/include/system_srv.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024 Jiri Svoboda + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @addtogroup libsystem + * @{ + */ +/** @file System control protocol server stub + */ + +#ifndef _LIBSYSTEM_SYSTEM_SRV_H_ +#define _LIBSYSTEM_SYSTEM_SRV_H_ + +#include +#include + +typedef struct system_ops system_ops_t; + +/** System server structure (per client session) */ +typedef struct { + async_sess_t *client_sess; + system_ops_t *ops; + void *arg; +} system_srv_t; + +struct system_ops { + errno_t (*shutdown)(void *); +}; + +extern void system_conn(ipc_call_t *, system_srv_t *); +extern void system_srv_initialize(system_srv_t *); +extern void system_srv_shutdown_complete(system_srv_t *); +extern void system_srv_shutdown_failed(system_srv_t *); + +#endif + +/** @} + */ diff --git a/uspace/lib/system/include/types/system.h b/uspace/lib/system/include/types/system.h new file mode 100644 index 0000000000..5161bb6471 --- /dev/null +++ b/uspace/lib/system/include/types/system.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024 Jiri Svoboda + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @addtogroup libsystem + * @{ + */ +/** @file System control service interface + */ + +#ifndef _LIBSYSTEM_TYPES_SYSTEM_H_ +#define _LIBSYSTEM_TYPES_SYSTEM_H_ + +/** System control service callbacks */ +typedef struct { + /** Shutdown completed successfully */ + void (*shutdown_complete)(void *); + /** Shutdown failed */ + void (*shutdown_failed)(void *); +} system_cb_t; + +struct system; +typedef struct system system_t; + +#endif + +/** @} + */ diff --git a/uspace/lib/system/meson.build b/uspace/lib/system/meson.build new file mode 100644 index 0000000000..ef7f215e73 --- /dev/null +++ b/uspace/lib/system/meson.build @@ -0,0 +1,37 @@ +# +# Copyright (c) 2024 Jiri Svoboda +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# - The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +src = files( + 'src/system.c', + 'src/system_srv.c' +) + +test_src = files( + 'test/main.c', + 'test/system.c' +) diff --git a/uspace/lib/system/private/system.h b/uspace/lib/system/private/system.h new file mode 100644 index 0000000000..0af09225a0 --- /dev/null +++ b/uspace/lib/system/private/system.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024 Jiri Svoboda + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @addtogroup libsystem + * @{ + */ +/** @file System control service interface + */ + +#ifndef _LIBSYSTEM_PRIVATE_SYSTEM_H_ +#define _LIBSYSTEM_PRIVATE_SYSTEM_H_ + +#include +#include + +/** System control service session */ +struct system { + /** Session with system control service */ + async_sess_t *sess; + /** Callbacks */ + system_cb_t *cb; + /** Argument to callback functions */ + void *cb_arg; + /** Synchronize access to system object */ + fibril_mutex_t lock; + /** @c true if callback handler terminated */ + bool cb_done; + /** Signalled when cb_done or ev_pending is changed */ + fibril_condvar_t cv; +}; + +#endif + +/** @} + */ diff --git a/uspace/lib/system/src/system.c b/uspace/lib/system/src/system.c new file mode 100644 index 0000000000..a488b0a17b --- /dev/null +++ b/uspace/lib/system/src/system.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2024 Jiri Svoboda + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @addtogroup libsystem + * @{ + */ +/** @file System control service interface + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../private/system.h" + +static errno_t system_callback_create(system_t *); +static void system_cb_conn(ipc_call_t *, void *); + +/** Open system control service. + * + * @param svcname Service name + * @param cb Pointer to callback structure + * @param arg Argument passed to callback functions + * @param rsystem Place to store pointer to system control service object. + * + * @return EOK on success or an error code + */ +errno_t system_open(const char *svcname, system_cb_t *cb, void *arg, + system_t **rsystem) +{ + service_id_t system_svc; + async_sess_t *sess; + system_t *system; + errno_t rc; + + system = calloc(1, sizeof(system_t)); + if (system == NULL) + return ENOMEM; + + fibril_mutex_initialize(&system->lock); + fibril_condvar_initialize(&system->cv); + + rc = loc_service_get_id(svcname, &system_svc, IPC_FLAG_BLOCKING); + if (rc != EOK) + goto error; + + sess = loc_service_connect(system_svc, INTERFACE_SYSTEM, + IPC_FLAG_BLOCKING); + if (sess == NULL) + goto error; + + system->sess = sess; + system->cb = cb; + system->cb_arg = arg; + + rc = system_callback_create(system); + if (rc != EOK) { + async_hangup(sess); + goto error; + } + + *rsystem = system; + return EOK; +error: + free(system); + return rc; +} + +/** Close system control service. + * + * @param system System control service + */ +void system_close(system_t *system) +{ + fibril_mutex_lock(&system->lock); + async_hangup(system->sess); + system->sess = NULL; + + /* Wait for callback handler to terminate */ + + while (!system->cb_done) + fibril_condvar_wait(&system->cv, &system->lock); + fibril_mutex_unlock(&system->lock); + + free(system); +} + +/** Create callback connection from system control service. + * + * @param system System control service + * @return EOK on success or an error code + */ +static errno_t system_callback_create(system_t *system) +{ + async_exch_t *exch = async_exchange_begin(system->sess); + + aid_t req = async_send_0(exch, SYSTEM_CALLBACK_CREATE, NULL); + + port_id_t port; + errno_t rc = async_create_callback_port(exch, INTERFACE_SYSTEM_CB, 0, 0, + system_cb_conn, system, &port); + + async_exchange_end(exch); + + if (rc != EOK) + return rc; + + errno_t retval; + async_wait_for(req, &retval); + + return retval; +} + +/** Shut the system down. + * + * This function is asynchronous. It returns immediately with success + * if the system started shutting down. Once shutdown is completed, + * the @c shutdown_complete callback is executed. If the shutdown fails, + * the @c shutdown_fail callback is executed. + * + * @param system System control service + * @return EOK on succes or an error code + */ +errno_t system_shutdown(system_t *system) +{ + async_exch_t *exch = async_exchange_begin(system->sess); + errno_t rc = async_req_0_0(exch, SYSTEM_SHUTDOWN); + async_exchange_end(exch); + + return rc; +} + +/** System shutdown completed. + * + * @param system System control service + * @param icall Call data + */ +static void system_shutdown_complete(system_t *system, ipc_call_t *icall) +{ + if (system->cb != NULL && system->cb->shutdown_complete != NULL) + system->cb->shutdown_complete(system->cb_arg); + + async_answer_0(icall, EOK); +} + +/** System shutdown failed. + * + * @param system System control service + * @param icall Call data + */ +static void system_shutdown_failed(system_t *system, ipc_call_t *icall) +{ + if (system->cb != NULL && system->cb->shutdown_complete != NULL) + system->cb->shutdown_failed(system->cb_arg); + + async_answer_0(icall, EOK); +} + +/** Callback connection handler. + * + * @param icall Connect call data + * @param arg Argument, system_t * + */ +static void system_cb_conn(ipc_call_t *icall, void *arg) +{ + system_t *system = (system_t *) arg; + + while (true) { + ipc_call_t call; + async_get_call(&call); + + if (!ipc_get_imethod(&call)) { + /* Hangup */ + async_answer_0(&call, EOK); + goto out; + } + + switch (ipc_get_imethod(&call)) { + case SYSTEM_SHUTDOWN_COMPLETE: + system_shutdown_complete(system, &call); + break; + case SYSTEM_SHUTDOWN_FAILED: + system_shutdown_failed(system, &call); + break; + default: + async_answer_0(&call, ENOTSUP); + break; + } + } + +out: + fibril_mutex_lock(&system->lock); + system->cb_done = true; + fibril_mutex_unlock(&system->lock); + fibril_condvar_broadcast(&system->cv); +} + +/** @} + */ diff --git a/uspace/lib/system/src/system_srv.c b/uspace/lib/system/src/system_srv.c new file mode 100644 index 0000000000..651b7dc56f --- /dev/null +++ b/uspace/lib/system/src/system_srv.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2024 Jiri Svoboda + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @addtogroup libsystem + * @{ + */ +/** + * @file + * @brief System control protocol server stub + */ + +#include +#include +#include +#include +#include +#include +#include + +static void system_callback_create_srv(system_srv_t *srv, ipc_call_t *call) +{ + async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE); + if (sess == NULL) { + async_answer_0(call, ENOMEM); + return; + } + + srv->client_sess = sess; + async_answer_0(call, EOK); +} + +static void system_shutdown_srv(system_srv_t *srv, ipc_call_t *icall) +{ + errno_t rc; + + if (srv->ops->shutdown == NULL) { + async_answer_0(icall, ENOTSUP); + return; + } + + rc = srv->ops->shutdown(srv->arg); + async_answer_0(icall, rc); +} + +void system_conn(ipc_call_t *icall, system_srv_t *srv) +{ + /* Accept the connection */ + async_accept_0(icall); + + while (true) { + ipc_call_t call; + + async_get_call(&call); + sysarg_t method = ipc_get_imethod(&call); + + if (!method) { + /* The other side has hung up */ + async_answer_0(&call, EOK); + break; + } + + switch (method) { + case SYSTEM_CALLBACK_CREATE: + system_callback_create_srv(srv, &call); + break; + case SYSTEM_SHUTDOWN: + system_shutdown_srv(srv, &call); + break; + default: + async_answer_0(&call, ENOTSUP); + } + } + + /* Hang up callback session */ + if (srv->client_sess != NULL) { + async_hangup(srv->client_sess); + srv->client_sess = NULL; + } +} + +/** Initialize system server structure + * + * @param srv System server structure to initialize + */ +void system_srv_initialize(system_srv_t *srv) +{ + memset(srv, 0, sizeof(*srv)); +} + +/** Send 'shutdown complete' event to client. + * + * @param srv System server structure + */ +void system_srv_shutdown_complete(system_srv_t *srv) +{ + async_exch_t *exch; + + exch = async_exchange_begin(srv->client_sess); + async_msg_0(exch, SYSTEM_SHUTDOWN_COMPLETE); + async_exchange_end(exch); +} + +/** Send 'shutdown failed' event to client. + * + * @param srv System server structure + */ +void system_srv_shutdown_failed(system_srv_t *srv) +{ + async_exch_t *exch; + + exch = async_exchange_begin(srv->client_sess); + async_msg_0(exch, SYSTEM_SHUTDOWN_FAILED); + async_exchange_end(exch); +} + +/** @} + */ diff --git a/uspace/lib/system/test/main.c b/uspace/lib/system/test/main.c new file mode 100644 index 0000000000..45307c3c99 --- /dev/null +++ b/uspace/lib/system/test/main.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024 Jiri Svoboda + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +PCUT_INIT; + +PCUT_IMPORT(system); + +PCUT_MAIN(); diff --git a/uspace/lib/system/test/system.c b/uspace/lib/system/test/system.c new file mode 100644 index 0000000000..8ab6154997 --- /dev/null +++ b/uspace/lib/system/test/system.c @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2024 Jiri Svoboda + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../private/system.h" + +PCUT_INIT; + +PCUT_TEST_SUITE(system); + +static const char *test_system_server = "test-system"; +static const char *test_system_svc = "test/system"; + +void test_system_conn(ipc_call_t *, void *); + +static errno_t test_shutdown(void *); + +static void test_sys_shutdown_complete(void *); +static void test_sys_shutdown_failed(void *); + +static system_ops_t test_system_srv_ops = { + .shutdown = test_shutdown +}; + +system_cb_t test_system_cb = { + .shutdown_complete = test_sys_shutdown_complete, + .shutdown_failed = test_sys_shutdown_failed +}; + +/** Describes to the server how to respond to our request and pass tracking + * data back to the client. + */ +typedef struct { + errno_t rc; + + bool shutdown_called; + bool shutdown_complete_called; + bool shutdown_failed_called; + + fibril_condvar_t event_cv; + fibril_mutex_t event_lock; + system_srv_t *srv; +} test_response_t; + +/** system_open(), system_close() work for valid system control service */ +PCUT_TEST(open_close) +{ + errno_t rc; + service_id_t sid; + system_t *system = NULL; + test_response_t resp; + loc_srv_t *srv; + + async_set_fallback_port_handler(test_system_conn, &resp); + + // FIXME This causes this test to be non-reentrant! + rc = loc_server_register(test_system_server, &srv); + PCUT_ASSERT_ERRNO_VAL(EOK, rc); + + rc = loc_service_register(srv, test_system_svc, &sid); + PCUT_ASSERT_ERRNO_VAL(EOK, rc); + + rc = system_open(test_system_svc, NULL, NULL, &system); + PCUT_ASSERT_ERRNO_VAL(EOK, rc); + PCUT_ASSERT_NOT_NULL(system); + + system_close(system); + rc = loc_service_unregister(srv, sid); + PCUT_ASSERT_ERRNO_VAL(EOK, rc); + loc_server_unregister(srv); +} + +/** system_shutdown() with server returning error response works */ +PCUT_TEST(shutdown_failure) +{ + errno_t rc; + service_id_t sid; + system_t *system = NULL; + test_response_t resp; + loc_srv_t *srv; + + async_set_fallback_port_handler(test_system_conn, &resp); + + // FIXME This causes this test to be non-reentrant! + rc = loc_server_register(test_system_server, &srv); + PCUT_ASSERT_ERRNO_VAL(EOK, rc); + + rc = loc_service_register(srv, test_system_svc, &sid); + PCUT_ASSERT_ERRNO_VAL(EOK, rc); + + rc = system_open(test_system_svc, NULL, NULL, &system); + PCUT_ASSERT_ERRNO_VAL(EOK, rc); + PCUT_ASSERT_NOT_NULL(system); + + resp.rc = ENOMEM; + resp.shutdown_called = false; + + rc = system_shutdown(system); + PCUT_ASSERT_TRUE(resp.shutdown_called); + PCUT_ASSERT_ERRNO_VAL(resp.rc, rc); + + system_close(system); + rc = loc_service_unregister(srv, sid); + PCUT_ASSERT_ERRNO_VAL(EOK, rc); + loc_server_unregister(srv); +} + +/** system_shutdown() with server returning success response works */ +PCUT_TEST(shutdown_success) +{ + errno_t rc; + service_id_t sid; + system_t *system = NULL; + test_response_t resp; + loc_srv_t *srv; + + async_set_fallback_port_handler(test_system_conn, &resp); + + // FIXME This causes this test to be non-reentrant! + rc = loc_server_register(test_system_server, &srv); + PCUT_ASSERT_ERRNO_VAL(EOK, rc); + + rc = loc_service_register(srv, test_system_svc, &sid); + PCUT_ASSERT_ERRNO_VAL(EOK, rc); + + rc = system_open(test_system_svc, NULL, NULL, &system); + PCUT_ASSERT_ERRNO_VAL(EOK, rc); + PCUT_ASSERT_NOT_NULL(system); + + resp.rc = EOK; + resp.shutdown_called = false; + + rc = system_shutdown(system); + PCUT_ASSERT_TRUE(resp.shutdown_called); + PCUT_ASSERT_ERRNO_VAL(resp.rc, rc); + + system_close(system); + rc = loc_service_unregister(srv, sid); + PCUT_ASSERT_ERRNO_VAL(EOK, rc); + loc_server_unregister(srv); +} + +/** 'Shutdown complete' event is delivered from server to client callback + * function. + */ +PCUT_TEST(shutdown_complete) +{ + errno_t rc; + service_id_t sid; + system_t *system = NULL; + test_response_t resp; + loc_srv_t *srv; + + async_set_fallback_port_handler(test_system_conn, &resp); + + // FIXME This causes this test to be non-reentrant! + rc = loc_server_register(test_system_server, &srv); + PCUT_ASSERT_ERRNO_VAL(EOK, rc); + + rc = loc_service_register(srv, test_system_svc, &sid); + PCUT_ASSERT_ERRNO_VAL(EOK, rc); + + rc = system_open(test_system_svc, &test_system_cb, &resp, &system); + PCUT_ASSERT_ERRNO_VAL(EOK, rc); + PCUT_ASSERT_NOT_NULL(system); + PCUT_ASSERT_NOT_NULL(resp.srv); + + resp.shutdown_complete_called = false; + fibril_mutex_initialize(&resp.event_lock); + fibril_condvar_initialize(&resp.event_cv); + system_srv_shutdown_complete(resp.srv); + + /* Wait for the event handler to be called. */ + fibril_mutex_lock(&resp.event_lock); + while (!resp.shutdown_complete_called) { + fibril_condvar_wait(&resp.event_cv, &resp.event_lock); + } + fibril_mutex_unlock(&resp.event_lock); + + system_close(system); + + rc = loc_service_unregister(srv, sid); + PCUT_ASSERT_ERRNO_VAL(EOK, rc); + loc_server_unregister(srv); +} + +/** 'Shutdown failed' event is delivered from server to client callback + * function. + */ +PCUT_TEST(shutdown_failed) +{ + errno_t rc; + service_id_t sid; + system_t *system = NULL; + test_response_t resp; + loc_srv_t *srv; + + async_set_fallback_port_handler(test_system_conn, &resp); + + // FIXME This causes this test to be non-reentrant! + rc = loc_server_register(test_system_server, &srv); + PCUT_ASSERT_ERRNO_VAL(EOK, rc); + + rc = loc_service_register(srv, test_system_svc, &sid); + PCUT_ASSERT_ERRNO_VAL(EOK, rc); + + rc = system_open(test_system_svc, &test_system_cb, &resp, &system); + PCUT_ASSERT_ERRNO_VAL(EOK, rc); + PCUT_ASSERT_NOT_NULL(system); + PCUT_ASSERT_NOT_NULL(resp.srv); + + resp.shutdown_failed_called = false; + fibril_mutex_initialize(&resp.event_lock); + fibril_condvar_initialize(&resp.event_cv); + system_srv_shutdown_failed(resp.srv); + + /* Wait for the event handler to be called. */ + fibril_mutex_lock(&resp.event_lock); + while (!resp.shutdown_failed_called) { + fibril_condvar_wait(&resp.event_cv, &resp.event_lock); + } + fibril_mutex_unlock(&resp.event_lock); + + system_close(system); + + rc = loc_service_unregister(srv, sid); + PCUT_ASSERT_ERRNO_VAL(EOK, rc); + loc_server_unregister(srv); +} + +/** Test system control service connection. */ +void test_system_conn(ipc_call_t *icall, void *arg) +{ + test_response_t *resp = (test_response_t *)arg; + system_srv_t srv; + + /* Set up protocol structure */ + system_srv_initialize(&srv); + srv.ops = &test_system_srv_ops; + srv.arg = arg; + resp->srv = &srv; + + /* Handle connection */ + system_conn(icall, &srv); + + resp->srv = NULL; +} + +/** Test system shutdown. + * + * @param arg Argument (test_response_t *) + */ +static errno_t test_shutdown(void *arg) +{ + test_response_t *resp = (test_response_t *)arg; + + resp->shutdown_called = true; + return resp->rc; +} + +/** Test system shutdown complete. + * + * @param arg Argument (test_response_t *) + */ +static void test_sys_shutdown_complete(void *arg) +{ + test_response_t *resp = (test_response_t *)arg; + + resp->shutdown_complete_called = true; + fibril_condvar_signal(&resp->event_cv); +} + +/** Test system shutdown failed. + * + * @param arg Argument (test_response_t *) + */ +static void test_sys_shutdown_failed(void *arg) +{ + test_response_t *resp = (test_response_t *)arg; + + resp->shutdown_failed_called = true; +} + +PCUT_EXPORT(system);