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
worker(void * arg)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
get_worker(void)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 if (!w->func)
73 return w;
74 }
75
76 return NULL;
77 }
78
G_begin_execute(void (* func)(void *),void * closure,void ** ref,int force)79 void 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
G_end_execute(void ** ref)108 void 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
G_init_workers(void)121 void 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
G_finish_workers(void)140 void 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
G_begin_execute(void (* func)(void *),void * closure,void ** ref,int force)167 void G_begin_execute(void (*func)(void *), void *closure, void **ref, int force)
168 {
169 (*func)(closure);
170 }
171
G_end_execute(void ** ref)172 void G_end_execute(void **ref)
173 {
174 }
175
G_init_workers(void)176 void G_init_workers(void)
177 {
178 }
179
G_finish_workers(void)180 void G_finish_workers(void)
181 {
182 }
183
184 /****************************************************************************/
185
186 #endif
187
188