GRASS GIS 8 Programmer's Manual  8.5.0dev(2024)-d6dec75dd4
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 
27 struct 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 
37 static int num_workers;
38 static struct worker *workers;
39 static pthread_cond_t worker_cond;
40 static pthread_mutex_t worker_mutex;
41 
42 /****************************************************************************/
43 
44 static 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 
66 static 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 
73  if (!w->func)
74  return w;
75  }
76 
77  return NULL;
78 }
79 
80 void G_begin_execute(void (*func)(void *), void *closure, void **ref, int force)
81 {
82  struct worker *w;
83 
84  if (*ref)
85  G_fatal_error(_("Task already has a worker"));
86 
87  pthread_mutex_lock(&worker_mutex);
88 
89  while (w = get_worker(), force && num_workers > 0 && !w)
90  pthread_cond_wait(&worker_cond, &worker_mutex);
91  *ref = w;
92 
93  if (!w) {
94  pthread_mutex_unlock(&worker_mutex);
95  (*func)(closure);
96  return;
97  }
98 
99  pthread_mutex_lock(&w->mutex);
100  w->func = func;
101  w->closure = closure;
102  w->ref = ref;
103  pthread_cond_signal(&w->cond);
104  pthread_mutex_unlock(&w->mutex);
105 
106  pthread_mutex_unlock(&worker_mutex);
107 }
108 
109 void G_end_execute(void **ref)
110 {
111  struct worker *w = *ref;
112 
113  if (!w)
114  return;
115 
116  pthread_mutex_lock(&w->mutex);
117  while (*ref)
118  pthread_cond_wait(&w->cond, &w->mutex);
119  pthread_mutex_unlock(&w->mutex);
120 }
121 
122 void G_init_workers(void)
123 {
124  const char *p = getenv("WORKERS");
125  int i;
126 
127  pthread_mutex_init(&worker_mutex, NULL);
128  pthread_cond_init(&worker_cond, NULL);
129 
130  num_workers = p ? atoi(p) : DEFAULT_WORKERS;
131  workers = G_calloc(num_workers, sizeof(struct worker));
132 
133  for (i = 0; i < num_workers; i++) {
134  struct worker *w = &workers[i];
135 
136  pthread_mutex_init(&w->mutex, NULL);
137  pthread_cond_init(&w->cond, NULL);
138  pthread_create(&w->thread, NULL, worker, w);
139  }
140 }
141 
142 void G_finish_workers(void)
143 {
144  int i;
145 
146  for (i = 0; i < num_workers; i++) {
147  struct worker *w = &workers[i];
148 
149  w->cancel = 1;
150  pthread_cancel(w->thread);
151  }
152 
153  for (i = 0; i < num_workers; i++) {
154  struct worker *w = &workers[i];
155 
156  pthread_join(w->thread, NULL);
157  pthread_mutex_destroy(&w->mutex);
158  pthread_cond_destroy(&w->cond);
159  }
160 
161  pthread_mutex_destroy(&worker_mutex);
162  pthread_cond_destroy(&worker_cond);
163 }
164 
165 /****************************************************************************/
166 
167 #else
168 
169 /****************************************************************************/
170 
171 void G_begin_execute(void (*func)(void *), void *closure, void **ref UNUSED,
172  int force UNUSED)
173 {
174  (*func)(closure);
175 }
176 
177 void G_end_execute(void **ref UNUSED)
178 {
179 }
180 
181 void G_init_workers(void)
182 {
183 }
184 
186 {
187 }
188 
189 /****************************************************************************/
190 
191 #endif
#define NULL
Definition: ccmath.h:32
#define G_calloc(m, n)
Definition: defs/gis.h:95
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
#define UNUSED
A macro for an attribute, if attached to a variable, indicating that the variable is not used.
Definition: gis.h:47
#define _(str)
Definition: glocale.h:10
void G_end_execute(void **ref UNUSED)
Definition: worker.c:177
void G_init_workers(void)
Definition: worker.c:181
void G_finish_workers(void)
Definition: worker.c:185
void G_begin_execute(void(*func)(void *), void *closure, void **ref UNUSED, int force UNUSED)
Definition: worker.c:171