summaryrefslogtreecommitdiffstats
path: root/lib/frr_pthread.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/frr_pthread.h')
-rw-r--r--lib/frr_pthread.h270
1 files changed, 270 insertions, 0 deletions
diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h
new file mode 100644
index 0000000..89519ab
--- /dev/null
+++ b/lib/frr_pthread.h
@@ -0,0 +1,270 @@
+/*
+ * Utilities and interfaces for managing POSIX threads within FRR.
+ * Copyright (C) 2017 Cumulus Networks, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_PTHREAD_H
+#define _FRR_PTHREAD_H
+
+#include <pthread.h>
+#include "frratomic.h"
+#include "memory.h"
+#include "frrcu.h"
+#include "thread.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define OS_THREAD_NAMELEN 16
+
+struct frr_pthread;
+struct frr_pthread_attr;
+
+struct frr_pthread_attr {
+ void *(*start)(void *);
+ int (*stop)(struct frr_pthread *, void **);
+};
+
+struct frr_pthread {
+
+ /*
+ * Mutex protecting this structure. Must be taken for reading some
+ * fields, denoted by a 'Requires: mtx'.
+ */
+ pthread_mutex_t mtx;
+
+ /* pthread id */
+ pthread_t thread;
+
+ struct rcu_thread *rcu_thread;
+
+ /* thread master for this pthread's thread.c event loop */
+ struct thread_master *master;
+
+ /* caller-specified data; start & stop funcs, name, id */
+ struct frr_pthread_attr attr;
+
+ /*
+ * Notification mechanism for allowing pthreads to notify their parents
+ * when they are ready to do work. This mechanism has two associated
+ * functions:
+ *
+ * - frr_pthread_wait_running()
+ * This function should be called by the spawning thread after
+ * frr_pthread_run(). It safely waits until the spawned thread
+ * indicates that is ready to do work by posting to the condition
+ * variable.
+ *
+ * - frr_pthread_notify_running()
+ * This function should be called by the spawned thread when it is
+ * ready to do work. It will wake up any threads waiting on the
+ * previously described condition.
+ */
+ pthread_cond_t *running_cond;
+ pthread_mutex_t *running_cond_mtx;
+ atomic_bool running;
+
+ /*
+ * Fake thread-specific storage. No constraints on usage. Helpful when
+ * creating reentrant pthread implementations. Can be used to pass
+ * argument to pthread entry function.
+ *
+ * Requires: mtx
+ */
+ void *data;
+
+ /*
+ * Human-readable thread name.
+ *
+ * Requires: mtx
+ */
+ char *name;
+
+ /* Used in pthread_set_name max 16 characters */
+ char os_name[OS_THREAD_NAMELEN];
+};
+
+extern const struct frr_pthread_attr frr_pthread_attr_default;
+
+/*
+ * Initializes this module.
+ *
+ * Must be called before using any of the other functions.
+ */
+void frr_pthread_init(void);
+
+/*
+ * Uninitializes this module.
+ *
+ * Destroys all registered frr_pthread's and internal data structures.
+ *
+ * It is safe to call frr_pthread_init() after this function to reinitialize
+ * the module.
+ */
+void frr_pthread_finish(void);
+
+/*
+ * Creates a new frr_pthread with the given attributes.
+ *
+ * The 'attr' argument should be filled out with the desired attributes,
+ * including ID, start and stop functions and the desired name. Alternatively,
+ * if attr is NULL, the default attributes will be used. The pthread will be
+ * set up to run a basic threadmaster loop and the name will be "Anonymous".
+ * Scheduling tasks onto the threadmaster in the 'master' field of the returned
+ * frr_pthread will cause them to run on that pthread.
+ *
+ * @param attr - the thread attributes
+ * @param name - Human-readable name
+ * @param os_name - 16 characters (including '\0') thread name to set in os,
+ * @return the created frr_pthread upon success, or NULL upon failure
+ */
+struct frr_pthread *frr_pthread_new(const struct frr_pthread_attr *attr,
+ const char *name, const char *os_name);
+
+/*
+ * Changes the name of the frr_pthread as reported by the operating
+ * system.
+ *
+ * @param fpt - the frr_pthread to operate on
+ * @return - on success returns 0 otherwise nonzero error number.
+ */
+int frr_pthread_set_name(struct frr_pthread *fpt);
+
+/*
+ * Destroys an frr_pthread.
+ *
+ * Assumes that the associated pthread, if any, has already terminated.
+ *
+ * @param fpt - the frr_pthread to destroy
+ */
+void frr_pthread_destroy(struct frr_pthread *fpt);
+
+/*
+ * Creates a new pthread and binds it to a frr_pthread.
+ *
+ * This function is a wrapper for pthread_create. The first parameter is the
+ * frr_pthread to bind the created pthread to. All subsequent arguments are
+ * passed unmodified to pthread_create(). The frr_pthread * provided will be
+ * used as the argument to the pthread entry function. If it is necessary to
+ * pass additional data, the 'data' field in the frr_pthread may be used.
+ *
+ * This function returns the same code as pthread_create(). If the value is
+ * zero, the provided frr_pthread is bound to a running POSIX thread. If the
+ * value is less than zero, the provided frr_pthread is guaranteed to be a
+ * clean instance that may be susbsequently passed to frr_pthread_run().
+ *
+ * @param fpt - frr_pthread * to run
+ * @param attr - see pthread_create(3)
+ *
+ * @return see pthread_create(3)
+ */
+int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr);
+
+/*
+ * Waits until the specified pthread has finished setting up and is ready to
+ * begin work.
+ *
+ * If the pthread's code makes use of the startup synchronization mechanism,
+ * this function should be called before attempting to use the functionality
+ * exposed by the pthread. It waits until the 'running' condition is satisfied
+ * (see struct definition of frr_pthread).
+ *
+ * @param fpt - the frr_pthread * to wait on
+ */
+void frr_pthread_wait_running(struct frr_pthread *fpt);
+
+/*
+ * Notifies other pthreads that the calling thread has finished setting up and
+ * is ready to begin work.
+ *
+ * This will allow any other pthreads waiting in 'frr_pthread_wait_running' to
+ * proceed.
+ *
+ * @param fpt - the frr_pthread * that has finished setting up
+ */
+void frr_pthread_notify_running(struct frr_pthread *fpt);
+
+/*
+ * Stops a frr_pthread with a result.
+ *
+ * @param fpt - frr_pthread * to stop
+ * @param result - where to store the thread's result, if any. May be NULL if a
+ * result is not needed.
+ */
+int frr_pthread_stop(struct frr_pthread *fpt, void **result);
+
+/* Stops all frr_pthread's. */
+void frr_pthread_stop_all(void);
+
+#ifndef HAVE_PTHREAD_CONDATTR_SETCLOCK
+#define pthread_condattr_setclock(A, B)
+#endif
+
+/* mutex auto-lock/unlock */
+
+/* variant 1:
+ * (for short blocks, multiple mutexes supported)
+ * break & return can be used for aborting the block
+ *
+ * frr_with_mutex(&mtx, &mtx2) {
+ * if (error)
+ * break;
+ * ...
+ * }
+ */
+#define _frr_with_mutex(mutex) \
+ *NAMECTR(_mtx_) __attribute__(( \
+ unused, cleanup(_frr_mtx_unlock))) = _frr_mtx_lock(mutex), \
+ /* end */
+
+#define frr_with_mutex(...) \
+ for (pthread_mutex_t MACRO_REPEAT(_frr_with_mutex, ##__VA_ARGS__) \
+ *_once = NULL; _once == NULL; _once = (void *)1) \
+ /* end */
+
+/* variant 2:
+ * (more suitable for long blocks, no extra indentation)
+ *
+ * frr_mutex_lock_autounlock(&mtx);
+ * ...
+ */
+#define frr_mutex_lock_autounlock(mutex) \
+ pthread_mutex_t *NAMECTR(_mtx_) \
+ __attribute__((unused, cleanup(_frr_mtx_unlock))) = \
+ _frr_mtx_lock(mutex) \
+ /* end */
+
+static inline pthread_mutex_t *_frr_mtx_lock(pthread_mutex_t *mutex)
+{
+ pthread_mutex_lock(mutex);
+ return mutex;
+}
+
+static inline void _frr_mtx_unlock(pthread_mutex_t **mutex)
+{
+ if (!*mutex)
+ return;
+ pthread_mutex_unlock(*mutex);
+ *mutex = NULL;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FRR_PTHREAD_H */