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