File Coverage

third_party/modest/source/mycore/mythread.c
Criterion Covered Total %
statement 88 159 55.3
branch 37 80 46.2
condition n/a
subroutine n/a
pod n/a
total 125 239 52.3


line stmt bran cond sub pod time code
1             /*
2             Copyright (C) 2015-2017 Alexander Borisov
3            
4             This library is free software; you can redistribute it and/or
5             modify it under the terms of the GNU Lesser General Public
6             License as published by the Free Software Foundation; either
7             version 2.1 of the License, or (at your option) any later version.
8            
9             This library is distributed in the hope that it will be useful,
10             but WITHOUT ANY WARRANTY; without even the implied warranty of
11             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12             Lesser General Public License for more details.
13            
14             You should have received a copy of the GNU Lesser General Public
15             License along with this library; if not, write to the Free Software
16             Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17            
18             Author: lex.borisov@gmail.com (Alexander Borisov)
19             */
20              
21             #include "mycore/mythread.h"
22              
23             #ifndef MyCORE_BUILD_WITHOUT_THREADS
24              
25 22           mythread_t * mythread_create(void)
26             {
27 22           return mycore_calloc(1, sizeof(mythread_t));
28             }
29              
30 22           mystatus_t mythread_init(mythread_t *mythread, mythread_type_t type, size_t threads_count, size_t id_increase)
31             {
32 22 50         if(threads_count == 0)
33 0           return MyCORE_STATUS_ERROR;
34            
35 22           mythread->entries_size = threads_count;
36 22           mythread->entries_length = 0;
37 22           mythread->id_increase = id_increase;
38 22           mythread->type = type;
39            
40 22           mythread->entries = (mythread_entry_t*)mycore_calloc(mythread->entries_size, sizeof(mythread_entry_t));
41 22 50         if(mythread->entries == NULL)
42 0           return MyCORE_STATUS_ERROR_MEMORY_ALLOCATION;
43            
44 22           mythread->attr = mythread_thread_attr_init(mythread);
45 22 50         if(mythread->attr == NULL)
46 0           return MyCORE_STATUS_THREAD_ERROR_ATTR_INIT;
47            
48 22           mythread->timespec = mythread_nanosleep_create(mythread);
49            
50 22           return MyCORE_STATUS_OK;
51             }
52              
53 0           void mythread_clean(mythread_t *mythread)
54             {
55 0           mythread_thread_attr_clean(mythread, mythread->attr);
56 0           mythread_nanosleep_clean(mythread->timespec);
57            
58 0           mythread->sys_last_error = 0;
59 0           }
60              
61 22           mythread_t * mythread_destroy(mythread_t *mythread, mythread_callback_before_entry_join_f before_join, void* ctx, bool self_destroy)
62             {
63 22 50         if(mythread == NULL)
64 0           return NULL;
65            
66 22 50         if(mythread->entries) {
67 22           mythread_resume(mythread, MyTHREAD_OPT_QUIT);
68 22           mythread_quit(mythread, before_join, ctx);
69 22           mycore_free(mythread->entries);
70             }
71            
72 22           mythread_thread_attr_destroy(mythread, mythread->attr);
73 22           mythread_nanosleep_destroy(mythread->timespec);
74            
75 22 50         if(self_destroy) {
76 22           mycore_free(mythread);
77 22           return NULL;
78             }
79            
80 0           return mythread;
81             }
82              
83 22           mystatus_t myhread_entry_create(mythread_t *mythread, mythread_process_f process_func, mythread_work_f work_func, mythread_thread_opt_t opt)
84             {
85 22           mythread->sys_last_error = 0;
86            
87 22 50         if(mythread->entries_length >= mythread->entries_size)
88 0           return MyCORE_STATUS_THREAD_ERROR_NO_SLOTS;
89            
90 22           mythread_entry_t *entry = &mythread->entries[mythread->entries_length];
91            
92 22           entry->context.mythread = mythread;
93 22           entry->context.func = work_func;
94 22           entry->context.id = mythread->entries_length;
95 22           entry->context.t_count = mythread->entries_size;
96 22           entry->context.opt = opt;
97 22           entry->context.status = 0;
98            
99 22           entry->context.timespec = mythread_nanosleep_create(mythread);
100            
101 22           entry->context.mutex = mythread_mutex_create(mythread);
102 22 50         if(entry->context.mutex == NULL)
103 0           return MyCORE_STATUS_THREAD_ERROR_MUTEX_INIT;
104            
105 22 50         if(mythread_mutex_wait(mythread, entry->context.mutex)) {
106 0           mythread_mutex_close(mythread, entry->context.mutex);
107 0           return MyCORE_STATUS_THREAD_ERROR_MUTEX_LOCK;
108             }
109            
110 22           entry->thread = mythread_thread_create(mythread, process_func, &entry->context);
111 22 50         if(entry->thread == NULL) {
112 0           mythread_mutex_close(mythread, entry->context.mutex);
113 0           return MyCORE_STATUS_ERROR;
114             }
115            
116 22           mythread->entries_length++;
117            
118 22           return MyCORE_STATUS_OK;
119             }
120              
121 14           mythread_id_t myhread_increase_id_by_entry_id(mythread_t* mythread, mythread_id_t thread_id)
122             {
123 14           return mythread->id_increase + thread_id;
124             }
125              
126             /*
127             * Global functions, for all threads
128             */
129 0           mystatus_t mythread_join(mythread_t *mythread, mythread_callback_before_entry_join_f before_join, void* ctx)
130             {
131 0 0         for (size_t i = 0; i < mythread->entries_length; i++) {
132 0 0         if(before_join)
133 0           before_join(mythread, &mythread->entries[i], ctx);
134            
135 0 0         if(mythread_thread_join(mythread, mythread->entries[i].thread))
136 0           return MyCORE_STATUS_ERROR;
137             }
138            
139 0           return MyCORE_STATUS_OK;
140             }
141              
142 22           mystatus_t mythread_quit(mythread_t *mythread, mythread_callback_before_entry_join_f before_join, void* ctx)
143             {
144 22           mythread_option_set(mythread, MyTHREAD_OPT_QUIT);
145            
146 44 100         for (size_t i = 0; i < mythread->entries_length; i++)
147             {
148 22 100         if(before_join)
149 14           before_join(mythread, &mythread->entries[i], ctx);
150            
151 44           if(mythread_thread_join(mythread, mythread->entries[i].thread) ||
152 22           mythread_thread_destroy(mythread, mythread->entries[i].thread))
153             {
154 0           return MyCORE_STATUS_ERROR;
155             }
156             }
157            
158 22           return MyCORE_STATUS_OK;
159             }
160              
161 12           mystatus_t mythread_stop(mythread_t *mythread)
162             {
163 12 50         if(mythread->opt & MyTHREAD_OPT_STOP)
164 0           return MyCORE_STATUS_OK;
165            
166 12           mythread_option_set(mythread, MyTHREAD_OPT_STOP);
167            
168 24 100         for (size_t i = 0; i < mythread->entries_length; i++)
169             {
170 25 100         while((mythread->entries[i].context.opt & MyTHREAD_OPT_STOP) == 0) {
171 13           mythread_nanosleep_sleep(mythread->timespec);
172             }
173             }
174            
175 12           return MyCORE_STATUS_OK;
176             }
177              
178 24           mystatus_t mythread_suspend(mythread_t *mythread)
179             {
180 24 50         if(mythread->opt & MyTHREAD_OPT_WAIT)
181 0           return MyCORE_STATUS_OK;
182            
183 24           mythread_option_set(mythread, MyTHREAD_OPT_WAIT);
184            
185 48 100         for (size_t i = 0; i < mythread->entries_length; i++)
186             {
187 40 100         while((mythread->entries[i].context.opt & MyTHREAD_OPT_STOP) == 0 &&
    100          
188 28           (mythread->entries[i].context.opt & MyTHREAD_OPT_WAIT) == 0)
189             {
190 16           mythread_nanosleep_sleep(mythread->timespec);
191             }
192             }
193            
194 24           return MyCORE_STATUS_OK;
195             }
196              
197 66           mystatus_t mythread_resume(mythread_t *mythread, mythread_thread_opt_t send_opt)
198             {
199 66 100         if(mythread->opt & MyTHREAD_OPT_WAIT) {
200 24           mythread_option_set(mythread, send_opt);
201 24           return MyCORE_STATUS_OK;
202             }
203            
204 42           mythread_option_set(mythread, send_opt);
205            
206 84 100         for (size_t i = 0; i < mythread->entries_length; i++)
207             {
208 42 100         if(mythread->entries[i].context.opt & MyTHREAD_OPT_STOP) {
209 34           mythread->entries[i].context.opt = send_opt;
210            
211 34 50         if(mythread_mutex_post(mythread, mythread->entries[i].context.mutex))
212 0           return MyCORE_STATUS_ERROR;
213             }
214             }
215            
216 42           return MyCORE_STATUS_OK;
217             }
218              
219 6           mystatus_t mythread_check_status(mythread_t *mythread)
220             {
221 12 100         for (size_t i = 0; i < mythread->entries_length; i++)
222             {
223 6 50         if(mythread->entries[i].context.status)
224 0           return mythread->entries[i].context.status;
225             }
226            
227 6           return MyCORE_STATUS_OK;
228             }
229              
230 0           mythread_thread_opt_t mythread_option(mythread_t *mythread)
231             {
232 0           return mythread->opt;
233             }
234              
235 132           void mythread_option_set(mythread_t *mythread, mythread_thread_opt_t opt)
236             {
237 132           mythread->opt = opt;
238 132           }
239              
240             /*
241             * Entries functions, for all threads
242             */
243 0           mystatus_t mythread_entry_join(mythread_entry_t* entry, mythread_callback_before_entry_join_f before_join, void* ctx)
244             {
245 0 0         if(before_join)
246 0           before_join(entry->context.mythread, entry, ctx);
247            
248 0 0         if(mythread_thread_join(entry->context.mythread, entry->thread))
249 0           return MyCORE_STATUS_ERROR;
250            
251 0           return MyCORE_STATUS_OK;
252             }
253              
254 0           mystatus_t mythread_entry_quit(mythread_entry_t* entry, mythread_callback_before_entry_join_f before_join, void* ctx)
255             {
256 0 0         if(before_join)
257 0           before_join(entry->context.mythread, entry, ctx);
258            
259 0           if(mythread_thread_join(entry->context.mythread, entry->thread) ||
260 0           mythread_thread_destroy(entry->context.mythread, entry->thread))
261             {
262 0           return MyCORE_STATUS_ERROR;
263             }
264            
265 0           return MyCORE_STATUS_OK;
266             }
267              
268 0           mystatus_t mythread_entry_stop(mythread_entry_t* entry)
269             {
270 0 0         if(entry->context.opt & MyTHREAD_OPT_STOP)
271 0           return MyCORE_STATUS_OK;
272            
273 0           entry->context.opt = MyTHREAD_OPT_STOP;
274            
275 0 0         while((entry->context.opt & MyTHREAD_OPT_STOP) == 0) {
276 0           mythread_nanosleep_sleep(entry->context.mythread->timespec);
277             }
278            
279 0           return MyCORE_STATUS_OK;
280             }
281              
282 0           mystatus_t mythread_entry_suspend(mythread_entry_t* entry)
283             {
284 0 0         if(entry->context.opt & MyTHREAD_OPT_WAIT)
285 0           return MyCORE_STATUS_OK;
286            
287 0           entry->context.opt = MyTHREAD_OPT_WAIT;
288            
289 0 0         while((entry->context.opt & MyTHREAD_OPT_STOP) == 0 && (entry->context.opt & MyTHREAD_OPT_WAIT) == 0) {
    0          
290 0           mythread_nanosleep_sleep(entry->context.mythread->timespec);
291             }
292            
293 0           return MyCORE_STATUS_OK;
294             }
295              
296 0           mystatus_t mythread_entry_resume(mythread_entry_t* entry, mythread_thread_opt_t send_opt)
297             {
298 0 0         if(entry->context.opt & MyTHREAD_OPT_WAIT) {
299 0           entry->context.opt = send_opt;
300             }
301 0 0         else if(entry->context.opt & MyTHREAD_OPT_STOP) {
302 0           entry->context.opt = send_opt;
303            
304 0 0         if(mythread_mutex_post(entry->context.mythread, entry->context.mutex))
305 0           return MyCORE_STATUS_ERROR;
306             }
307             else
308 0           entry->context.opt = send_opt;
309            
310 0           return MyCORE_STATUS_OK;
311             }
312              
313 0           mystatus_t mythread_entry_status(mythread_entry_t* entry)
314             {
315 0           return entry->context.status;
316             }
317              
318 0           mythread_t * mythread_entry_mythread(mythread_entry_t* entry)
319             {
320 0           return entry->context.mythread;
321             }
322              
323             /* Callbacks */
324 14           void mythread_callback_quit(mythread_t* mythread, mythread_entry_t* entry, void* ctx)
325             {
326 14 50         while((entry->context.opt & MyTHREAD_OPT_QUIT) == 0)
327 0           mythread_nanosleep_sleep(mythread->timespec);
328 14           }
329              
330             #endif
331