[lib][tipc] Add helpers to simplify implementing event loops

This CL adds APIs to simplify implementation of event loops on top
of handle sets:

    tipc_hset_add_entry() - adds handle with associated event handler
                            to specified handle set
    tipc_hset_mod_entry() - modifies attributes (like event mask) for
                            handle previously attached to handle set
    tipc_hset_remove_entry() - removes specified handle form handle set
    tipc_handle_event() - wait on specified handle set and handle single
                          event
    tipc_run_event_loop() - run endless event loop

Bug: 134153462
Change-Id: Ib19dbe9c6454098992caadfa7fe7eb82339987b6
diff --git a/lib/tipc/include/lib/tipc/tipc.h b/lib/tipc/include/lib/tipc/tipc.h
index 8de6a56..9a25688 100644
--- a/lib/tipc/include/lib/tipc/tipc.h
+++ b/lib/tipc/include/lib/tipc/tipc.h
@@ -97,7 +97,7 @@
  * @chan: handle of the channel to receive message from
  * @min_sz: minimum size of the message expected
  * @buf1: pointer to buffer to store first segment of the message
- * @buf1_sz size of the buffer pointed by @buf1 parameter
+ * @buf1_sz: size of the buffer pointed by @buf1 parameter
  * @buf2: pointer to buffer to store second segment of the message
  * @buf2_sz: size of the buffer pointed by @buf2 parameter
  *
@@ -163,7 +163,7 @@
 void tipc_handle_chan_errors(const struct uevent* ev);
 
 /**
- * event_handler_proc_t - pointer to event handler routine
+ * typedef event_handler_proc_t - pointer to event handler routine
  * @ev: pointer to event to handle
  * @priv: handle/context specific argument
  *
@@ -172,13 +172,95 @@
 typedef void (*event_handler_proc_t)(const struct uevent* ev, void* priv);
 
 /**
- * struct tipc_event_handler: defines event handler for particular handle
+ * struct tipc_event_handler - defines event handler for particular handle
  * @proc: pointer to @event_handler_proc_t function to call to handle event
- * @priv: value to pass as @priv parameter of @event_handler_proc_t function
+ * @priv: value to pass as @priv parameter for event_handler_proc_t function
+ *        pointed by @proc parameters
  */
 struct tipc_event_handler {
     event_handler_proc_t proc;
     void* priv;
 };
 
+/*
+ * struct tipc_hset - opaque structure representing handle set
+ */
+struct tipc_hset;
+
+/**
+ *  tipc_hset_create() - allocate and initialize new handle set
+ *
+ *  Return: a pointer to &struct tipc_hset on success, PTR_ERR otherwise.
+ */
+struct tipc_hset* tipc_hset_create(void);
+
+/**
+ * tipc_hset_add_entry() - add new existing handle to handle set
+ * @hset:        pointer to valid &struct tipc_hset
+ * @handle:      handle to add to handle set specified by @hset parameter
+ * @evt_mask:    set of events allowed to be handled for @handle
+ * @evt_handler: pointer to initialized &struct tipc_event_handler (must not
+ *               be NULL) that will be used to handle events associated with
+ *               handle specified by @handle parameter and allowed by
+ *               @evt_mask parameter.
+ *
+ * Return: 0 on success, a negative error code otherwise
+ */
+int tipc_hset_add_entry(struct tipc_hset* hset,
+                        handle_t handle,
+                        uint32_t evt_mask,
+                        struct tipc_event_handler* evt_handler);
+
+/**
+ * tipc_hset_mod_entry() - modify parameters of an existing entry in handle set
+ * @hset:        pointer to valid &struct tipc_hset
+ * @handle:      handle to modify an entry for. It must be previously added by
+ *               calling tipc_hset_add_handle() function.
+ * @evt_mask:    set of events allowed to be handled for @handle
+ * @evt_handler: pointer to initialized &struct tipc_event_handler (must not
+ *               be NULL) that will be used to handle events associated with
+ *               handle specified by @handle parameter and allowed by
+ *               @evt_mask parameter.
+ *
+ * Return: 0 on success, a negative error code otherwise
+ */
+int tipc_hset_mod_entry(struct tipc_hset* hset,
+                        handle_t handle,
+                        uint32_t evt_mask,
+                        struct tipc_event_handler* evt_handler);
+
+/**
+ * tipc_hset_remove_entry() - remove specified handle from handle set
+ * @hset: pointer to &struct tipc_hset to remove handle from
+ * @handle: handle to remove from handle set specified by @hset parameter
+ *
+ * Return: 0 on success, a negative error code otherwise
+ */
+int tipc_hset_remove_entry(struct tipc_hset* hset, handle_t handle);
+
+/**
+ * tipc_handle_event() - wait on handle set and handle single event
+ * @hset: pointer to valid &struct tipc_hset set to get events from
+ * @timeout: a max amount of time to wait for event before returning to caller
+ *
+ * Note: It is expected that this routine is called repeatedly from event loop
+ * to handle events. The handle set specified as @hset parameter has to be
+ * populated with tipc_hset_add_handle() function.
+ *
+ * Return: 0 if an event has been retrieved and handled, ERR_TIMED_OUT if
+ * specified by @timeout parameter time has elapsed without getting new event,
+ * negative error code otherwise.
+ */
+int tipc_handle_event(struct tipc_hset* hset, uint32_t timeout);
+
+/**
+ * tipc_run_event_loop() - run standard event loop
+ * @hset: handle set to retrieve and handle events from
+ *
+ * This routine does not return under normal conditions.
+ *
+ * Return: negative error code if an error is encountered.
+ */
+int tipc_run_event_loop(struct tipc_hset* hset);
+
 __END_CDECLS
diff --git a/lib/tipc/tipc.c b/lib/tipc/tipc.c
index 6dbff56..c8b28b0 100644
--- a/lib/tipc/tipc.c
+++ b/lib/tipc/tipc.c
@@ -23,6 +23,8 @@
 
 #include <lib/tipc/tipc.h>
 
+#include "tipc_priv.h"
+
 int tipc_connect(handle_t* handle_p, const char* port) {
     int rc;
 
@@ -180,3 +182,132 @@
         abort();
     }
 }
+
+/*
+ * Initialize an existing tipc_hset
+ */
+int tipc_hset_init(struct tipc_hset* hset) {
+    int rc;
+
+    assert(hset);
+
+    hset->handle = INVALID_IPC_HANDLE;
+
+    rc = handle_set_create();
+    if (rc < 0)
+        return rc;
+
+    hset->handle = (handle_t)rc;
+    return 0;
+}
+
+/*
+ * Allocate and initialize new handle set structure
+ */
+struct tipc_hset* tipc_hset_create(void) {
+    struct tipc_hset* hset;
+
+    hset = malloc(sizeof(struct tipc_hset));
+    if (!hset)
+        return (void*)(uintptr_t)(ERR_NO_MEMORY);
+
+    int rc = tipc_hset_init(hset);
+    if (rc < 0) {
+        free(hset);
+        return (void*)(uintptr_t)(rc);
+    }
+
+    return hset;
+}
+
+/*
+ * Add handle to handle set
+ */
+int tipc_hset_add_entry(struct tipc_hset* hset,
+                        handle_t handle,
+                        uint32_t evt_mask,
+                        struct tipc_event_handler* evt_handler) {
+    struct uevent uevt = {
+            .handle = handle,
+            .event = evt_mask,
+            .cookie = (void*)evt_handler,
+    };
+
+    if (!hset || !evt_handler)
+        return ERR_INVALID_ARGS;
+
+    assert(evt_handler->proc);
+
+    /* attach new entry */
+    return handle_set_ctrl(hset->handle, HSET_ADD, &uevt);
+}
+
+/*
+ * Modify handle set entry
+ */
+int tipc_hset_mod_entry(struct tipc_hset* hset,
+                        handle_t handle,
+                        uint32_t evt_mask,
+                        struct tipc_event_handler* evt_handler) {
+    struct uevent uevt = {
+            .handle = handle,
+            .event = evt_mask,
+            .cookie = (void*)evt_handler,
+    };
+
+    if (!hset || !evt_handler)
+        return ERR_INVALID_ARGS;
+
+    assert(evt_handler->proc);
+
+    /* modify entry */
+    return handle_set_ctrl(hset->handle, HSET_MOD, &uevt);
+}
+
+/*
+ * Remove handle from handle set
+ */
+int tipc_hset_remove_entry(struct tipc_hset* hset, handle_t h) {
+    struct uevent uevt = {
+            .handle = h,
+            .event = 0,
+            .cookie = NULL,
+    };
+
+    if (!hset)
+        return ERR_INVALID_ARGS;
+
+    /* detach entry */
+    return handle_set_ctrl(hset->handle, HSET_DEL, &uevt);
+}
+
+int tipc_handle_event(struct tipc_hset* hset, uint32_t timeout) {
+    int rc;
+    struct uevent evt = UEVENT_INITIAL_VALUE(evt);
+
+    if (!hset)
+        return ERR_INVALID_ARGS;
+
+    /* wait for next event up to specified time */
+    rc = wait(hset->handle, &evt, timeout);
+    if (rc < 0)
+        return rc;
+
+    /* get handler */
+    struct tipc_event_handler* handler = evt.cookie;
+
+    /* invoke it */
+    handler->proc(&evt, handler->priv);
+
+    return 0;
+}
+
+int tipc_run_event_loop(struct tipc_hset* hset) {
+    int rc;
+
+    do {
+        rc = tipc_handle_event(hset, INFINITE_TIME);
+    } while (rc == 0);
+
+    return rc;
+}
diff --git a/lib/tipc/tipc_priv.h b/lib/tipc/tipc_priv.h
new file mode 100644
index 0000000..9ba0bcc
--- /dev/null
+++ b/lib/tipc/tipc_priv.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <lk/compiler.h>
+#include <trusty_ipc.h>
+
+__BEGIN_CDECLS
+
+/**
+ * struct tipc_hset - structure to wrap underlying handle set handle
+ * @handle:  handle of underlying handle set
+ */
+struct tipc_hset {
+    handle_t handle;
+};
+
+/**
+ * tipc_hset_init() - initialize specified tipc handles set
+ * @hset: pointer to &struct tipc_hset to initialize
+ *
+ * Creates a new handle set and store it's handle in @handle field of
+ * wrapper structure
+ *
+ * Return: 0 on success, a negative error code otherwise
+ */
+int tipc_hset_init(struct tipc_hset* hset);
+
+__END_CDECLS