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