lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <176246793955.2862242.13813774537220961463.stgit@frogsfrogsfrogs>
Date: Thu, 06 Nov 2025 14:35:51 -0800
From: "Darrick J. Wong" <djwong@...nel.org>
To: tytso@....edu
Cc: linux-ext4@...r.kernel.org
Subject: [PATCH 18/19] libsupport: add background thread manager

From: Darrick J. Wong <djwong@...nel.org>

Add some simple code to manage a background thread that wakes up
periodically.  This will be needed for MMP in fuse2fs, among other
things.

Signed-off-by: "Darrick J. Wong" <djwong@...nel.org>
---
 lib/support/bthread.h   |   27 ++++++
 lib/support/Makefile.in |    6 +
 lib/support/bthread.c   |  201 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 233 insertions(+), 1 deletion(-)
 create mode 100644 lib/support/bthread.h
 create mode 100644 lib/support/bthread.c


diff --git a/lib/support/bthread.h b/lib/support/bthread.h
new file mode 100644
index 00000000000000..cb29a655b815e5
--- /dev/null
+++ b/lib/support/bthread.h
@@ -0,0 +1,27 @@
+/*
+ * bthread.h - Background thread manager
+ *
+ * Copyright (C) 2025 Oracle.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+#ifndef __BTHREAD_H__
+#define __BTHREAD_H__
+
+typedef void (*bthread_fn_t)(void *data);
+struct bthread;
+
+int bthread_create(const char *name, bthread_fn_t fn, void *data,
+		   unsigned int period, struct bthread **btp);
+void bthread_destroy(struct bthread **btp);
+
+int bthread_start(struct bthread *bt);
+void bthread_stop(struct bthread *bt);
+
+int bthread_cancel(struct bthread *bt);
+int bthread_cancelled(struct bthread *bt);
+
+#endif /* __BTHREAD_H__ */
diff --git a/lib/support/Makefile.in b/lib/support/Makefile.in
index 3f26cd30172f51..6383816fd99cd4 100644
--- a/lib/support/Makefile.in
+++ b/lib/support/Makefile.in
@@ -13,7 +13,8 @@ MKDIR_P = @MKDIR_P@
 
 all::
 
-OBJS=		cstring.o \
+OBJS=		bthread.o \
+		cstring.o \
 		mkquota.o \
 		plausible.o \
 		profile.o \
@@ -28,6 +29,7 @@ OBJS=		cstring.o \
 		devname.o
 
 SRCS=		$(srcdir)/argv_parse.c \
+		$(srcdir)/bthread.c \
 		$(srcdir)/cstring.c \
 		$(srcdir)/mkquota.c \
 		$(srcdir)/parse_qtype.c \
@@ -108,6 +110,8 @@ $(OBJS):
 #
 argv_parse.o: $(srcdir)/argv_parse.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(srcdir)/argv_parse.h
+bthread.o: $(srcdir)/bthread.c $(top_builddir)/lib/config.h \
+ $(srcdir)/bthread.h
 cstring.o: $(srcdir)/cstring.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(srcdir)/cstring.h
 mkquota.o: $(srcdir)/mkquota.c $(top_builddir)/lib/config.h \
diff --git a/lib/support/bthread.c b/lib/support/bthread.c
new file mode 100644
index 00000000000000..f59fde976920f9
--- /dev/null
+++ b/lib/support/bthread.c
@@ -0,0 +1,201 @@
+/*
+ * bthread.c - Background thread manager
+ *
+ * Copyright (C) 2025 Oracle.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+#include "config.h"
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <string.h>
+
+#include "support/bthread.h"
+
+enum bthread_state {
+	/* waiting to be put in the running state */
+	BT_WAITING,
+	/* running */
+	BT_RUNNING,
+	/* cancelled */
+	BT_CANCELLED,
+};
+
+struct bthread {
+	enum bthread_state state;
+	pthread_t thread;
+	pthread_mutex_t lock;
+	pthread_cond_t cond;
+	bthread_fn_t fn;
+	void *data;
+	unsigned int period; /* seconds */
+	int can_join:1;
+};
+
+/* Wait for a signal or for the periodic interval */
+static inline int bthread_wait(struct bthread *bt)
+{
+	struct timespec ts;
+
+	clock_gettime(CLOCK_REALTIME, &ts);
+	ts.tv_sec += bt->period;
+	return pthread_cond_timedwait(&bt->cond, &bt->lock, &ts);
+}
+
+static void *bthread_run(void *arg)
+{
+	struct bthread *bt = arg;
+	int ret;
+
+	while (1) {
+		pthread_mutex_lock(&bt->lock);
+		ret = bthread_wait(bt);
+		switch (bt->state) {
+		case BT_WAITING:
+			/* waiting to be runnable, go around again */
+			pthread_mutex_unlock(&bt->lock);
+			break;
+		case BT_RUNNING:
+			/* running; call our function if we timed out */
+			pthread_mutex_unlock(&bt->lock);
+			if (ret == ETIMEDOUT)
+				bt->fn(bt->data);
+			break;
+		case BT_CANCELLED:
+			/* exit if we're cancelled */
+			pthread_mutex_unlock(&bt->lock);
+			return NULL;
+		}
+	}
+
+	return NULL;
+}
+
+/* Create background thread and have it wait to be started */
+int bthread_create(const char *name,  bthread_fn_t fn, void *data,
+		   unsigned int period, struct bthread **btp)
+{
+	struct bthread *bt;
+	int error;
+
+	if (!period)
+		return EINVAL;
+
+	bt = calloc(1, sizeof(struct bthread));
+	if (!bt)
+		return ENOMEM;
+	bt->state = BT_WAITING;
+	bt->fn = fn;
+	bt->data = data;
+	bt->period = period;
+	bt->can_join = 1;
+
+	bt->lock = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
+	bt->cond = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
+
+	error = pthread_create(&bt->thread, NULL, bthread_run, bt);
+	if (error)
+		goto out_cond;
+
+	pthread_setname_np(bt->thread, name);
+
+	*btp = bt;
+	return 0;
+
+out_cond:
+	pthread_cond_destroy(&bt->cond);
+	pthread_mutex_destroy(&bt->lock);
+	free(bt);
+	return error;
+}
+
+/* Stop the thread (if running) and tear everything down */
+void bthread_destroy(struct bthread **btp)
+{
+	struct bthread *bt = *btp;
+
+	if (bt) {
+		bthread_stop(bt);
+
+		pthread_cond_destroy(&bt->cond);
+		pthread_mutex_destroy(&bt->lock);
+
+		free(bt);
+	}
+
+	*btp = NULL;
+}
+
+/* Start background thread, put it in waiting state */
+int bthread_start(struct bthread *bt)
+{
+	int err;
+
+	pthread_mutex_lock(&bt->lock);
+	bt->state = BT_RUNNING;
+	err = pthread_cond_signal(&bt->cond);
+	pthread_mutex_unlock(&bt->lock);
+
+	return err;
+}
+
+/* Has this thread been cancelled? */
+int bthread_cancelled(struct bthread *bt)
+{
+	int ret;
+
+	pthread_mutex_lock(&bt->lock);
+	ret = bt->state == BT_CANCELLED;
+	pthread_mutex_unlock(&bt->lock);
+
+	return ret;
+}
+
+/* Ask the thread to cancel itself, but don't wait */
+int bthread_cancel(struct bthread *bt)
+{
+	int err = 0;
+
+	pthread_mutex_lock(&bt->lock);
+	switch (bt->state) {
+	case BT_CANCELLED:
+		break;
+	case BT_WAITING:
+	case BT_RUNNING:
+		bt->state = BT_CANCELLED;
+		err = pthread_cond_signal(&bt->cond);
+		break;
+	}
+	pthread_mutex_unlock(&bt->lock);
+
+	return err;
+}
+
+/* Ask the thread to cancel itself and wait for it */
+void bthread_stop(struct bthread *bt)
+{
+	int need_join = 0;
+
+	pthread_mutex_lock(&bt->lock);
+	switch (bt->state) {
+	case BT_CANCELLED:
+		need_join = bt->can_join;
+		break;
+	case BT_WAITING:
+	case BT_RUNNING:
+		bt->state = BT_CANCELLED;
+		need_join = 1;
+		pthread_cond_signal(&bt->cond);
+		break;
+	}
+	if (need_join)
+		bt->can_join = 0;
+	pthread_mutex_unlock(&bt->lock);
+
+	if (need_join)
+		pthread_join(bt->thread, NULL);
+}


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ