GRASS GIS 7 Programmer's Manual  7.9.dev(2021)-e5379bbd7
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  if (!w->func)
73  return w;
74  }
75 
76  return NULL;
77 }
78 
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 
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 
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 
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 
167 void G_begin_execute(void (*func)(void *), void *closure, void **ref, int force)
168 {
169  (*func)(closure);
170 }
171 
172 void G_end_execute(void **ref)
173 {
174 }
175 
176 void G_init_workers(void)
177 {
178 }
179 
181 {
182 }
183 
184 /****************************************************************************/
185 
186 #endif
187 
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_end_execute(void **ref)
Definition: worker.c:172
#define NULL
Definition: ccmath.h:32
#define G_calloc(m, n)
Definition: defs/gis.h:113
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_init_workers(void)
Definition: worker.c:176
#define _(str)
Definition: glocale.h:10
char * getenv()