aboutsummaryrefslogtreecommitdiffstats
path: root/bus.h
diff options
context:
space:
mode:
Diffstat (limited to 'bus.h')
-rw-r--r--bus.h325
1 files changed, 325 insertions, 0 deletions
diff --git a/bus.h b/bus.h
new file mode 100644
index 0000000..707c9e4
--- /dev/null
+++ b/bus.h
@@ -0,0 +1,325 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef BUS_H
+#define BUS_H
+
+
+#ifndef _DEFAULT_SOURCE
+# define _DEFAULT_SOURCE
+#endif
+#include <sys/types.h>
+#include <time.h>
+
+
+
+#if defined(__GNUC__)
+# define BUS_COMPILER_GCC(X) X
+#else
+# define BUS_COMPILER_GCC(X) /* ignore */
+#endif
+
+
+
+/**
+ * Open the bus for reading only
+ */
+#define BUS_RDONLY 1
+
+/**
+ * Open the bus for writing only
+ */
+#define BUS_WRONLY 0
+
+/**
+ * Open the bus for both reading and writing only
+ */
+#define BUS_RDWR 0
+
+/**
+ * Fail to create bus if its file already exists
+ */
+#define BUS_EXCL 2
+
+/**
+ * Fail if interrupted
+ */
+#define BUS_INTR 4
+
+/**
+ * Function shall fail with errno set to `EAGAIN`
+ * if the it would block and this flag is used
+ */
+#define BUS_NOWAIT 1
+
+
+
+/**
+ * The number of bytes in storeable in the shared memory,
+ * note that this includes the NUL-termination.
+ * This means that message can be at most one byte smaller.
+ */
+#define BUS_MEMORY_SIZE 2048
+
+
+
+/**
+ * Bus information
+ */
+typedef struct bus
+{
+ /**
+ * The key for the semaphore array
+ */
+ key_t key_sem;
+
+ /**
+ * The key for the shared memory
+ */
+ key_t key_shm;
+
+ /**
+ * The ID of the semaphore array
+ */
+ int sem_id;
+
+ /**
+ * The address of the shared memory
+ */
+ char *message;
+
+ /**
+ * Non-zero if and only if `bus_poll` has not been
+ * called since the last `bus_poll_start`, or
+ * if `bus_poll` failed during reading
+ */
+ int first_poll;
+
+} bus_t;
+
+
+
+/**
+ * Create a new bus
+ *
+ * @param file The pathname of the bus, `NULL` to create a random one
+ * @param flags `BUS_EXCL` (if `file` is not `NULL`) to fail if the file
+ * already exists, otherwise if the file exists, nothing
+ * will happen;
+ * `BUS_INTR` to fail if interrupted
+ * @param out_file Output parameter for the pathname of the bus
+ * @return 0 on success, -1 on error
+ */
+BUS_COMPILER_GCC(__attribute__((__warn_unused_result__)))
+int bus_create(const char *restrict, int, char **restrict);
+
+/**
+ * Remove a bus
+ *
+ * @param file The pathname of the bus
+ * @return 0 on success, -1 on error
+ */
+BUS_COMPILER_GCC(__attribute__((__nonnull__)))
+int bus_unlink(const char *);
+
+
+/**
+ * Open an existing bus
+ *
+ * @param bus Bus information to fill
+ * @param file The filename of the bus
+ * @param flags `BUS_RDONLY`, `BUS_WRONLY` or `BUS_RDWR`,
+ * the value must not be negative
+ * @return 0 on success, -1 on error
+ */
+BUS_COMPILER_GCC(__attribute__((__nonnull__, __warn_unused_result__)))
+int bus_open(bus_t *restrict, const char *restrict, int);
+
+/**
+ * Close a bus
+ *
+ * @param bus Bus information
+ * @return 0 on success, -1 on error
+ */
+BUS_COMPILER_GCC(__attribute__((__nonnull__)))
+int bus_close(bus_t *);
+
+
+/**
+ * Broadcast a message on a bus
+ *
+ * @param bus Bus information
+ * @param message The message to write, may not be longer than
+ * `BUS_MEMORY_SIZE` including the NUL-termination
+ * @param flags `BUS_NOWAIT` if this function shall fail if
+ * another process is currently running this
+ * procedure
+ * @return 0 on success, -1 on error
+ */
+BUS_COMPILER_GCC(__attribute__((__nonnull__, __warn_unused_result__)))
+int bus_write(const bus_t *, const char *, int);
+
+/**
+ * Broadcast a message on a bus
+ *
+ * @param bus Bus information
+ * @param message The message to write, may not be longer than
+ * `BUS_MEMORY_SIZE` including the NUL-termination
+ * @param timeout The time the operation shall fail with errno set
+ * to `EAGAIN` if not completed
+ * @param clockid The ID of the clock the `timeout` is measured with,
+ * it most be a predictable clock
+ * @return 0 on success, -1 on error
+ */
+BUS_COMPILER_GCC(__attribute__((__nonnull__(1, 2), __warn_unused_result__)))
+int bus_write_timed(const bus_t *, const char *, const struct timespec *, clockid_t);
+
+
+/**
+ * Listen (in a loop, forever) for new message on a bus
+ *
+ * @param bus Bus information
+ * @param callback Function to call when a message is received, the
+ * (message, user_data) input parameters will be the read message and
+ * `user_data` from `bus_read`'s parameter with the
+ * same name. The message must have been parsed or
+ * copied when `callback` returns as it may be over
+ * overridden after that time. `callback` should
+ * return either of the the values:
+ * * 0: stop listening
+ * * 1: continue listening
+ * * -1: an error has occurred
+ * However, the function [`bus_read`] will invoke
+ * `callback` with `message` set to `NULL`one time
+ * directly after it has started listening on the
+ * bus. This is to the the program now it can safely
+ * continue with any action that requires that the
+ * programs is listening on the bus.
+ * @param user_data Parameter passed to `callback`
+ * @return 0 on success, -1 on error
+ */
+BUS_COMPILER_GCC(__attribute__((__nonnull__(1, 2), __warn_unused_result__)))
+int bus_read(const bus_t *restrict, int (*)(const char *, void *), void *);
+
+/**
+ * Listen (in a loop, forever) for new message on a bus
+ *
+ * @param bus Bus information
+ * @param callback Function to call when a message is received, the
+ * (message, user_data) input parameters will be the read message and
+ * `user_data` from `bus_read`'s parameter with the
+ * same name. The message must have been parsed or
+ * copied when `callback` returns as it may be over
+ * overridden after that time. `callback` should
+ * return either of the the values:
+ * * 0: stop listening
+ * * 1: continue listening
+ * * -1: an error has occurred
+ * However, the function [`bus_read`] will invoke
+ * `callback` with `message` set to `NULL`one time
+ * directly after it has started listening on the
+ * bus. This is to the the program now it can safely
+ * continue with any action that requires that the
+ * programs is listening on the bus.
+ * @param user_data Parameter passed to `callback`
+ * @param timeout The time the operation shall fail with errno set
+ * to `EAGAIN` if not completed, note that the callback
+ * function may or may not have been called
+ * @param clockid The ID of the clock the `timeout` is measured with,
+ * it most be a predictable clock
+ * @return 0 on success, -1 on error
+ */
+BUS_COMPILER_GCC(__attribute__((__nonnull__(1, 2), __warn_unused_result__)))
+int bus_read_timed(const bus_t *restrict, int (*)(const char *, void *),
+ void *, const struct timespec *, clockid_t);
+
+
+/**
+ * Announce that the thread is listening on the bus.
+ * This is required so the will does not miss any
+ * messages due to race conditions. Additionally,
+ * not calling this function will cause the bus the
+ * misbehave, is `bus_poll` is written to expect
+ * this function to have been called.
+ *
+ * @param bus Bus information
+ * @return 0 on success, -1 on error
+ */
+BUS_COMPILER_GCC(__attribute__((__nonnull__, __warn_unused_result__)))
+int bus_poll_start(bus_t *);
+
+/**
+ * Announce that the thread has stopped listening on the bus.
+ * This is required so that the thread does not cause others
+ * to wait indefinitely.
+ *
+ * @param bus Bus information
+ * @return 0 on success, -1 on error
+ */
+BUS_COMPILER_GCC(__attribute__((__nonnull__, __warn_unused_result__)))
+int bus_poll_stop(const bus_t *);
+
+/**
+ * Wait for a message to be broadcasted on the bus.
+ * The caller should make a copy of the received message,
+ * without freeing the original copy, and parse it in a
+ * separate thread. When the new thread has started be
+ * started, the caller of this function should then
+ * either call `bus_poll` again or `bus_poll_stop`.
+ *
+ * @param bus Bus information
+ * @param flags `BUS_NOWAIT` if the bus should fail and set `errno` to
+ * `EAGAIN` if there isn't already a message available on the bus
+ * @return The received message, `NULL` on error
+ */
+BUS_COMPILER_GCC(__attribute__((__nonnull__, __warn_unused_result__)))
+const char *bus_poll(bus_t *, int);
+
+/**
+ * Wait for a message to be broadcasted on the bus.
+ * The caller should make a copy of the received message,
+ * without freeing the original copy, and parse it in a
+ * separate thread. When the new thread has started be
+ * started, the caller of this function should then
+ * either call `bus_poll_timed` again or `bus_poll_stop`.
+ *
+ * @param bus Bus information
+ * @param timeout The time the operation shall fail with errno set
+ * to `EAGAIN` if not completed
+ * @param clockid The ID of the clock the `timeout` is measured with,
+ * it most be a predictable clock
+ * @return The received message, `NULL` on error
+ */
+BUS_COMPILER_GCC(__attribute__((__nonnull__(1), __warn_unused_result__)))
+const char *bus_poll_timed(bus_t *, const struct timespec *, clockid_t);
+
+
+/**
+ * Change the ownership of a bus
+ *
+ * `stat(2)` can be used of the bus's associated file to get the bus's ownership
+ *
+ * @param file The pathname of the bus
+ * @param owner The user ID of the bus's new owner
+ * @param group The group ID of the bus's new group
+ * @return 0 on success, -1 on error
+ */
+BUS_COMPILER_GCC(__attribute__((__nonnull__, __warn_unused_result__)))
+int bus_chown(const char *, uid_t, gid_t);
+
+/**
+ * Change the permissions for a bus
+ *
+ * `stat(2)` can be used of the bus's associated file to get the bus's permissions
+ *
+ * @param file The pathname of the bus
+ * @param mode The permissions of the bus, any permission for a user implies
+ * full permissions for that user, except only the owner may
+ * edit the bus's associated file
+ * @return 0 on success, -1 on error
+ */
+BUS_COMPILER_GCC(__attribute__((__nonnull__, __warn_unused_result__)))
+int bus_chmod(const char *, mode_t);
+
+
+
+#endif
+