1 #include <csignal>
2 #include <cstdio>
3 #include <cstdlib>
4 #include "xthread.h"
5 struct taskinfo definfo = {0,
6 #ifdef USE_PTHREAD
7 0
8 #endif
9 };
10
11 #ifndef nthreads
12
13 #define getrange1(range, ncpu) ((range) * (ncpu)) / nthreads
14 #define getrange2(range, ncpu) getrange1(range, (ncpu) + 1)
15
16 int ethreads = 0;
17 int nthreads = 1;
18
19 #ifdef USE_PTHREAD
20
21 /* Well conde follows is probably very ugly, since this is
22 * my absolutely first application for threads. Please let
23 * me know how to improvie it
24 */
25
26 static pthread_cond_t synccond, startcond;
27 static struct taskinfo infos[MAXTHREADS];
28 static pthread_mutex_t synccondmutex, startcondmutex;
29 pthread_mutex_t semaphors[MAXSEMAPHORS];
30 pthread_cond_t conds[MAXCONDS];
31
32 /*This loop is executed whole time in slave threads.
33 Its function is following:
34 1) wait for message
35 2) call function from message
36 3) synchronize
37 4) again
38
39 To invoke this mechanizm main thread(#1) should call
40 xth_function
41 xth_synchronize forces forces thread to wait for others
42 */
43
44 static int nfinished;
45 static int npending;
46 static int counter;
47 static int bcounter;
48 static int bcounter1;
49 static int range;
50 static void *data;
51 static xfunction function;
control_routine(void * i)52 static void *control_routine(void *i)
53 {
54 struct taskinfo *info = (struct taskinfo *)i;
55 int mycounter = 0;
56 int r;
57 void *d;
58 xfunction f;
59 while (1) {
60 /* quite a lot pthread calls. Please if you are
61 * reading this code and crying "OH NO!" so ugly
62 * handling! Why so much calls? Stop crying, I am
63 * newbie in threads. Please rewrite my code and
64 * send me better and faster version.
65 *
66 * This function comunicates with pth_function from main loop
67 * as follows: it uses startcond to wait for order start function!
68 * Counter is used to ensure that main function did not give
69 * order whie control_routine was busy
70 *
71 * after order is received, function address is read from global
72 * variables and started. Pth_function then executes its
73 * own part of calculation. After that it waits counter
74 * nfinished to reach number of thasks-1. This is done
75 * using cond synccond and synccondmutex. Quite complex
76 * but it seems to work. Looking forward for someone, who
77 * should reduce number of _lock/_unlock
78 */
79 pthread_mutex_lock(&synccondmutex);
80 nfinished++;
81 pthread_cond_signal(&synccond);
82 pthread_mutex_unlock(&synccondmutex);
83
84 pthread_mutex_lock(&startcondmutex);
85 while (mycounter >= counter) {
86 if (bcounter > bcounter1) {
87 /*Well we are already locked using start lock..should be OK */
88 mycounter--;
89 bcounter1++;
90 break;
91 }
92 pthread_cond_wait(&startcond, &startcondmutex);
93 }
94 r = range;
95 d = data;
96 f = function;
97 npending--;
98 pthread_mutex_unlock(&startcondmutex);
99 mycounter++;
100 f(d, info, getrange1(r, info->n), getrange2(r, info->n));
101 }
102 return NULL;
103 }
104
pth_init(int nthreads1)105 void pth_init(int nthreads1)
106 {
107 int i;
108 pthread_attr_t attr;
109 if (ethreads)
110 return;
111
112 if (nthreads1 == 1 || nthreads1 == 0)
113 return; /*use nothreads_* calls */
114 if (nthreads1 > MAXTHREADS)
115 nthreads1 = MAXTHREADS;
116 nthreads = nthreads1;
117
118 pthread_attr_init(&attr);
119 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
120
121 if (pthread_cond_init(&synccond, NULL))
122 exit(1);
123 if (pthread_cond_init(&startcond, NULL))
124 exit(1);
125 if (pthread_mutex_init(&synccondmutex, NULL))
126 exit(1);
127 if (pthread_mutex_init(&startcondmutex, NULL))
128 exit(1);
129
130 infos[0].n = 0;
131 /*infos[0].id = pthread_self(); */
132
133 for (i = 0; i < MAXSEMAPHORS; i++) {
134 pthread_mutex_init(semaphors + i, NULL);
135 }
136 for (i = 0; i < MAXCONDS; i++) {
137 pthread_cond_init(conds + i, NULL);
138 }
139
140 nfinished = 0;
141 for (i = 0; i < nthreads - 1; i++) {
142 if (pthread_create(&infos[i + 1].id, &attr, control_routine,
143 infos + i + 1)) {
144 nthreads = i + 1;
145 break;
146 }
147 infos[i + 1].n = i + 1;
148 }
149 if (nthreads != 1)
150 ethreads = 1;
151 }
152
pth_synchronize()153 void pth_synchronize()
154 {
155 /*Our job is done, synchronize now */
156 if (nfinished < nthreads - 1) {
157 pthread_mutex_lock(&synccondmutex);
158 while (nfinished < nthreads - 1) {
159 pthread_cond_wait(&synccond, &synccondmutex);
160 }
161 pthread_mutex_unlock(&synccondmutex);
162 }
163 /*Ok job is done, lets continue :) */
164 }
165
pth_bgjob(xfunction f,void * d)166 void pth_bgjob(xfunction f, void *d)
167 {
168 pthread_mutex_lock(&startcondmutex);
169 if (npending) {
170 printf("Collision!\n"); /*FIXME:remove this..I just want to know how
171 often this happends */
172 pthread_mutex_unlock(&startcondmutex);
173 f(d, infos, 0, 0);
174 }
175 if (bcounter < bcounter1) {
176 printf("Internal error\a\n");
177 }
178 if (!nfinished) {
179 pthread_mutex_unlock(&startcondmutex);
180 /*no more CPU available :( */
181 f(d, infos, 0, 0);
182 }
183 data = d;
184 range = 0;
185 function = f;
186 bcounter++;
187 nfinished--;
188 npending++;
189 pthread_cond_signal(&startcond);
190 pthread_mutex_unlock(&startcondmutex);
191 }
192
pth_function(xfunction f,void * d,int r)193 void pth_function(xfunction f, void *d, int r)
194 {
195 pth_synchronize();
196 pthread_mutex_lock(&startcondmutex);
197 data = d;
198 range = r;
199 function = f;
200 /*And lets start it:) */
201 nfinished = 0;
202 npending = nthreads - 1;
203 counter++;
204 if (nthreads == 2)
205 pthread_cond_signal(&startcond);
206 else
207 pthread_cond_broadcast(&startcond);
208 pthread_mutex_unlock(&startcondmutex);
209
210 function(data, infos, getrange1(range, 0), getrange2(range, 0));
211 }
212
pth_uninit()213 void pth_uninit()
214 {
215 /*Should be empty for now since all threads will be killed after exit call
216 */
217 /*FIXME should be added something if necessary :) */
218 nthreads = 1;
219 ethreads = 0;
220 }
221 #endif /*POSIX threads */
222 #endif /*nthreads */
223