aboutsummaryrefslogtreecommitdiff
path: root/src/parallel.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/parallel.c')
-rw-r--r--src/parallel.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/src/parallel.c b/src/parallel.c
new file mode 100644
index 0000000..0d63cd2
--- /dev/null
+++ b/src/parallel.c
@@ -0,0 +1,82 @@
+#include "parallel.h"
+
+#include <stdlib.h>
+
+#if defined(__unix__) || defined(__APPLE__)
+
+#include <pthread.h>
+#include <unistd.h>
+
+size_t psi_thread_count(void)
+{
+ long n = sysconf(_SC_NPROCESSORS_ONLN);
+ return n > 1 ? (size_t)n : 1;
+}
+
+struct PsiParallelTask
+{
+ void (*body)(size_t, size_t, void*);
+ void* ctx;
+ size_t start;
+ size_t end;
+};
+
+static void* worker(void* arg)
+{
+ struct PsiParallelTask* task = arg;
+ task->body(task->start, task->end, task->ctx);
+ return NULL;
+}
+
+void psi_parallel_for(size_t count, void (*body)(size_t, size_t, void*), void* ctx)
+{
+ size_t threads = psi_thread_count();
+ if (threads <= 1 || count <= 1)
+ {
+ body(0, count, ctx);
+ return;
+ }
+ if (threads > count)
+ threads = count;
+
+ pthread_t* handles = malloc(threads * sizeof *handles);
+ struct PsiParallelTask* tasks = malloc(threads * sizeof *tasks);
+ if (handles == NULL || tasks == NULL)
+ {
+ free(handles);
+ free(tasks);
+ body(0, count, ctx);
+ return;
+ }
+
+ size_t chunk = count / threads;
+ size_t remainder = count % threads;
+ size_t start = 0;
+ for (size_t t = 0; t < threads; t++)
+ {
+ size_t len = chunk + (t < remainder ? 1 : 0);
+ tasks[t] = (struct PsiParallelTask){ body, ctx, start, start + len };
+ start += len;
+ pthread_create(&handles[t], NULL, worker, &tasks[t]);
+ }
+
+ for (size_t t = 0; t < threads; t++)
+ pthread_join(handles[t], NULL);
+
+ free(handles);
+ free(tasks);
+}
+
+#else
+
+size_t psi_thread_count(void)
+{
+ return 1;
+}
+
+void psi_parallel_for(size_t count, void (*body)(size_t, size_t, void*), void* ctx)
+{
+ body(0, count, ctx);
+}
+
+#endif