GRASS GIS 8 Programmer's Manual 8.2.1(2023)-exported
worker.c
Go to the documentation of this file.
1/*!
2 * \file lib/gis/worker.c
3 *
4 * \brief GIS Library - Worker functions.
5 *
6 * (C) 2008-2014 by the GRASS Development Team
7 *
8 * This program is free software under the GNU General Public License
9 * (>=v2). Read the file COPYING that comes with GRASS for details.
10 *
11 * \author Glynn Clements
12 */
13
14#include <stdio.h>
15#include <stdlib.h>
16#include <grass/gis.h>
17#include <grass/glocale.h>
18
19#ifdef HAVE_PTHREAD_H
20
21/****************************************************************************/
22
23#include <pthread.h>
24
25#define DEFAULT_WORKERS 0
26
27struct worker {
28 void (*func)(void *);
29 void *closure;
30 void **ref;
31 pthread_t thread;
32 pthread_cond_t cond;
33 pthread_mutex_t mutex;
34 int cancel;
35};
36
37static int num_workers;
38static struct worker *workers;
39static pthread_cond_t worker_cond;
40static pthread_mutex_t worker_mutex;
41
42/****************************************************************************/
43
44static void *worker(void *arg)
45{
46 struct worker *w = arg;
47
48 while (!w->cancel) {
49 pthread_mutex_lock(&w->mutex);
50 while (!w->func)
51 pthread_cond_wait(&w->cond, &w->mutex);
52
53 (*w->func)(w->closure);
54
55 w->func = NULL;
56 w->closure = NULL;
57 *w->ref = NULL;
58 pthread_mutex_unlock(&w->mutex);
59 pthread_cond_signal(&w->cond);
60 pthread_cond_signal(&worker_cond);
61 }
62
63 return NULL;
64}
65
66static struct worker *get_worker(void)
67{
68 int i;
69
70 for (i = 0; i < num_workers; i++) {
71 struct worker *w = &workers[i];
72 if (!w->func)
73 return w;
74 }
75
76 return NULL;
77}
78
79void G_begin_execute(void (*func)(void *), void *closure, void **ref, int force)
80{
81 struct worker *w;
82
83 if (*ref)
84 G_fatal_error(_("Task already has a worker"));
85
86 pthread_mutex_lock(&worker_mutex);
87
88 while (w = get_worker(), force && num_workers > 0 && !w)
89 pthread_cond_wait(&worker_cond, &worker_mutex);
90 *ref = w;
91
92 if (!w) {
93 pthread_mutex_unlock(&worker_mutex);
94 (*func)(closure);
95 return;
96 }
97
98 pthread_mutex_lock(&w->mutex);
99 w->func = func;
100 w->closure = closure;
101 w->ref = ref;
102 pthread_cond_signal(&w->cond);
103 pthread_mutex_unlock(&w->mutex);
104
105 pthread_mutex_unlock(&worker_mutex);
106}
107
108void G_end_execute(void **ref)
109{
110 struct worker *w = *ref;
111
112 if (!w)
113 return;
114
115 pthread_mutex_lock(&w->mutex);
116 while (*ref)
117 pthread_cond_wait(&w->cond, &w->mutex);
118 pthread_mutex_unlock(&w->mutex);
119}
120
121void G_init_workers(void)
122{
123 const char *p = getenv("WORKERS");
124 int i;
125
126 pthread_mutex_init(&worker_mutex, NULL);
127 pthread_cond_init(&worker_cond, NULL);
128
129 num_workers = p ? atoi(p) : DEFAULT_WORKERS;
130 workers = G_calloc(num_workers, sizeof(struct worker));
131
132 for (i = 0; i < num_workers; i++) {
133 struct worker *w = &workers[i];
134 pthread_mutex_init(&w->mutex, NULL);
135 pthread_cond_init(&w->cond, NULL);
136 pthread_create(&w->thread, NULL, worker, w);
137 }
138}
139
140void G_finish_workers(void)
141{
142 int i;
143
144 for (i = 0; i < num_workers; i++) {
145 struct worker *w = &workers[i];
146 w->cancel = 1;
147 pthread_cancel(w->thread);
148 }
149
150 for (i = 0; i < num_workers; i++) {
151 struct worker *w = &workers[i];
152 pthread_join(w->thread, NULL);
153 pthread_mutex_destroy(&w->mutex);
154 pthread_cond_destroy(&w->cond);
155 }
156
157 pthread_mutex_destroy(&worker_mutex);
158 pthread_cond_destroy(&worker_cond);
159}
160
161/****************************************************************************/
162
163#else
164
165/****************************************************************************/
166
167void G_begin_execute(void (*func)(void *), void *closure, void **ref, int force)
168{
169 (*func)(closure);
170}
171
172void G_end_execute(void **ref)
173{
174}
175
177{
178}
179
181{
182}
183
184/****************************************************************************/
185
186#endif
187
#define NULL
Definition: ccmath.h:32
void G_fatal_error(const char *msg,...)
Print a fatal error message to stderr.
Definition: gis/error.c:160
void G_init_workers(void)
Definition: worker.c:176
void G_finish_workers(void)
Definition: worker.c:180
void G_begin_execute(void(*func)(void *), void *closure, void **ref, int force)
Definition: worker.c:167
void G_end_execute(void **ref)
Definition: worker.c:172