1 /*
2 Copyright (C) 2016-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 "modest/finder/thread.h"
22
23 /* private functions */
24 #ifndef MyCORE_BUILD_WITHOUT_THREADS
25 static void modest_finder_thread_stream(mythread_id_t thread_id, void* arg);
26 #else
27 static void modest_finder_thread_stream_single(modest_finder_thread_t* finder_thread, mycss_selectors_list_t* selector_list);
28 #endif
29
30 static modest_finder_thread_context_t * modest_finder_thread_create_context(modest_finder_thread_t* finder_thread, size_t count);
31 //static void modest_finder_thread_callback_found(modest_finder_t* finder, myhtml_tree_node_t* node, mycss_selectors_list_t* selector_list,
32 // mycss_selectors_entry_t* selector, mycss_selectors_specificity_t* spec, void* ctx);
33
34 /* basic functions */
modest_finder_thread_create(void)35 modest_finder_thread_t * modest_finder_thread_create(void)
36 {
37 return (modest_finder_thread_t*)mycore_calloc(1, sizeof(modest_finder_thread_t));
38 }
39
modest_finder_thread_init(modest_finder_t * finder,modest_finder_thread_t * finder_thread,size_t thread_count)40 mystatus_t modest_finder_thread_init(modest_finder_t* finder, modest_finder_thread_t* finder_thread, size_t thread_count)
41 {
42 #ifdef MyCORE_BUILD_WITHOUT_THREADS
43 thread_count = 1;
44 #endif
45
46 finder_thread->finder = finder;
47
48 /* objects for nodes */
49 finder_thread->entry_obj = mcobject_async_create();
50 if(finder_thread->entry_obj == NULL)
51 return MODEST_STATUS_OK;
52
53 mcobject_async_status_t mcstatus = mcobject_async_init(finder_thread->entry_obj, 128, 1024, sizeof(modest_finder_thread_entry_t));
54 if(mcstatus)
55 return MODEST_STATUS_OK;
56
57 /* objects for declarations */
58 finder_thread->declaration_obj = mcobject_async_create();
59 if(finder_thread->declaration_obj == NULL)
60 return MODEST_STATUS_OK;
61
62 mcstatus = mcobject_async_init(finder_thread->declaration_obj, 128, 1024, sizeof(modest_finder_thread_declaration_t));
63 if(mcstatus)
64 return MODEST_STATUS_OK;
65
66 finder_thread->context_list = modest_finder_thread_create_context(finder_thread, thread_count);
67 if(finder_thread->context_list == NULL)
68 return MODEST_STATUS_OK;
69
70 /* create and init threads */
71 #ifdef MyCORE_BUILD_WITHOUT_THREADS
72 finder_thread->thread = NULL;
73 #else
74 finder_thread->thread = mythread_create();
75
76 if(finder_thread->thread == NULL)
77 return MODEST_STATUS_OK;
78
79 mystatus_t status = mythread_init(finder_thread->thread, MyTHREAD_TYPE_STREAM, thread_count, 0);
80 if(status) {
81 mythread_destroy(finder_thread->thread, NULL, NULL, true);
82 return MODEST_STATUS_OK;
83 }
84
85 finder_thread->thread->context = finder_thread;
86
87 /* create threads */
88 for(size_t i = 0; i < finder_thread->thread->entries_size; i++) {
89 myhread_entry_create(finder_thread->thread, mythread_function, modest_finder_thread_stream, MyTHREAD_OPT_STOP);
90 }
91 #endif
92
93 return MODEST_STATUS_OK;
94 }
95
modest_finder_thread_clean(modest_finder_thread_t * finder_thread,bool self_destroy)96 void modest_finder_thread_clean(modest_finder_thread_t* finder_thread, bool self_destroy)
97 {
98 for(size_t i = 1; i < finder_thread->context_list_size; i++) {
99 mcobject_async_node_clean(finder_thread->entry_obj, finder_thread->context_list[i].entry_node_id);
100 mcobject_async_node_clean(finder_thread->declaration_obj, finder_thread->context_list[i].declaration_node_id);
101 }
102 }
103
modest_finder_thread_destroy(modest_finder_thread_t * finder_thread,bool self_destroy)104 modest_finder_thread_t * modest_finder_thread_destroy(modest_finder_thread_t* finder_thread, bool self_destroy)
105 {
106 if(finder_thread == NULL)
107 return NULL;
108
109 #ifndef MyCORE_BUILD_WITHOUT_THREADS
110 if(finder_thread->thread) {
111 finder_thread->thread = mythread_destroy(finder_thread->thread, mythread_callback_quit, NULL, true);
112 }
113 #endif
114
115 finder_thread->entry_obj = mcobject_async_destroy(finder_thread->entry_obj, true);
116 finder_thread->declaration_obj = mcobject_async_destroy(finder_thread->declaration_obj, true);
117
118 if(finder_thread->context_list) {
119 mycore_free(finder_thread->context_list);
120
121 finder_thread->context_list = NULL;
122 finder_thread->context_list_size = 0;
123 }
124
125 if(self_destroy) {
126 mycore_free(finder_thread);
127 return NULL;
128 }
129
130 return finder_thread;
131 }
132
modest_finder_thread_collate_node(modest_t * modest,myhtml_tree_node_t * node,modest_finder_thread_entry_t * entry)133 void modest_finder_thread_collate_node(modest_t* modest, myhtml_tree_node_t* node, modest_finder_thread_entry_t* entry)
134 {
135 modest_finder_thread_declaration_t* dec = entry->declaration;
136
137 while(dec) {
138 if(dec->entry)
139 modest_style_map_collate_declaration(modest, node, dec->entry, dec->entry->type, &dec->raw_spec);
140
141 dec = dec->next;
142 }
143 }
144
145 #ifdef MyCORE_BUILD_WITHOUT_THREADS
modest_finder_thread_process(modest_t * modest,modest_finder_thread_t * finder_thread,myhtml_tree_node_t * scope_node,mycss_selectors_list_t * selector_list)146 mystatus_t modest_finder_thread_process(modest_t* modest, modest_finder_thread_t* finder_thread,
147 myhtml_tree_node_t* scope_node, mycss_selectors_list_t* selector_list)
148 {
149 finder_thread->base_node = scope_node;
150 finder_thread->selector_list = selector_list;
151
152 if(finder_thread->finder == NULL)
153 return MODEST_STATUS_ERROR;
154
155 modest_finder_thread_stream_single(finder_thread, selector_list);
156
157 /* calc result */
158 modest_finder_thread_context_t* context = finder_thread->context_list;
159 myhtml_tree_node_t* node = scope_node;
160
161 /* compare results */
162 while(node) {
163 modest_finder_thread_entry_t* entry = context->entry;
164
165 while(entry) {
166 if(entry->node == node)
167 {
168 if(entry->next)
169 entry->next->prev = entry->prev;
170 else
171 context->entry_last = entry->prev;
172
173 if(entry->prev)
174 entry->prev->next = entry->next;
175 else
176 context->entry = entry->next;
177
178 modest_finder_thread_collate_node(modest, node, entry);
179 }
180
181 entry = entry->next;
182 }
183
184 if(node->child)
185 node = node->child;
186 else {
187 while(node != scope_node && node->next == NULL)
188 node = node->parent;
189
190 if(node == scope_node)
191 break;
192
193 node = node->next;
194 }
195 }
196
197 return MyCORE_STATUS_OK;
198 }
199
200 #else /* end def MyCORE_BUILD_WITHOUT_THREADS */
modest_finder_thread_process(modest_t * modest,modest_finder_thread_t * finder_thread,myhtml_tree_node_t * scope_node,mycss_selectors_list_t * selector_list)201 mystatus_t modest_finder_thread_process(modest_t* modest, modest_finder_thread_t* finder_thread,
202 myhtml_tree_node_t* scope_node, mycss_selectors_list_t* selector_list)
203 {
204 finder_thread->base_node = scope_node;
205 finder_thread->selector_list = selector_list;
206
207 if(finder_thread->finder == NULL)
208 return MODEST_STATUS_ERROR;
209
210 mythread_resume(finder_thread->thread, MyTHREAD_OPT_UNDEF);
211 modest_finder_thread_wait_for_all_done(finder_thread);
212
213 /* calc result */
214 modest_finder_thread_context_t* context_list = finder_thread->context_list;
215 myhtml_tree_node_t* node = scope_node;
216
217 /* compare results */
218 while(node) {
219 for(size_t i = 0; i < finder_thread->thread->entries_length; i++)
220 {
221 modest_finder_thread_context_t* context = &context_list[i];
222 modest_finder_thread_entry_t* entry = context->entry;
223
224 while(entry) {
225 if(entry->node == node)
226 {
227 if(entry->next)
228 entry->next->prev = entry->prev;
229 else
230 context->entry_last = entry->prev;
231
232 if(entry->prev)
233 entry->prev->next = entry->next;
234 else
235 context->entry = entry->next;
236
237 modest_finder_thread_collate_node(modest, node, entry);
238 }
239
240 entry = entry->next;
241 }
242 }
243
244 if(node->child)
245 node = node->child;
246 else {
247 while(node != scope_node && node->next == NULL)
248 node = node->parent;
249
250 if(node == scope_node)
251 break;
252
253 node = node->next;
254 }
255 }
256
257 return MODEST_STATUS_OK;
258 }
259
modest_finder_thread_wait_for_all_done(modest_finder_thread_t * finder_thread)260 void modest_finder_thread_wait_for_all_done(modest_finder_thread_t* finder_thread)
261 {
262 for (size_t idx = 0; idx < finder_thread->thread->entries_length; idx++) {
263 while((finder_thread->thread->entries[idx].context.opt & MyTHREAD_OPT_DONE) == 0) {
264 mythread_nanosleep_sleep(finder_thread->thread->timespec);
265 }
266 }
267 }
268 #endif /* if undef MyCORE_BUILD_WITHOUT_THREADS */
269
modest_finder_thread_create_context(modest_finder_thread_t * finder_thread,size_t count)270 modest_finder_thread_context_t * modest_finder_thread_create_context(modest_finder_thread_t* finder_thread, size_t count)
271 {
272 finder_thread->context_list_size = count;
273
274 modest_finder_thread_context_t *ctx = mycore_calloc(count, sizeof(modest_finder_thread_context_t));
275
276 if(ctx == NULL)
277 return NULL;
278
279 mcobject_async_status_t mcstatus;
280
281 for(size_t i = 0; i < count; i++) {
282 ctx[i].entry_node_id = mcobject_async_node_add(finder_thread->entry_obj, &mcstatus);
283
284 if(mcstatus) {
285 while(i) {
286 i--;
287 mcobject_async_node_delete(finder_thread->entry_obj, ctx[i].entry_node_id);
288 }
289
290 mycore_free(ctx);
291 return NULL;
292 }
293 }
294
295 for(size_t i = 0; i < count; i++) {
296 ctx[i].declaration_node_id = mcobject_async_node_add(finder_thread->declaration_obj, &mcstatus);
297
298 if(mcstatus) {
299 size_t t = count;
300 while(t > 1) {
301 t--;
302 mcobject_async_node_delete(finder_thread->entry_obj, ctx[t].entry_node_id);
303 }
304
305 while(i > 1) {
306 i--;
307 mcobject_async_node_delete(finder_thread->declaration_obj, ctx[i].declaration_node_id);
308 }
309
310 mycore_free(ctx);
311 return NULL;
312 }
313 }
314
315 return ctx;
316 }
317
modest_finder_thread_spec_is_up(modest_style_raw_specificity_t * spec_f,modest_style_raw_specificity_t * spec_t)318 bool modest_finder_thread_spec_is_up(modest_style_raw_specificity_t* spec_f, modest_style_raw_specificity_t* spec_t)
319 {
320 if(spec_f->x > spec_t->x)
321 return true;
322 else if(spec_f->x < spec_t->x)
323 return false;
324
325 if(spec_f->a > spec_t->a)
326 return true;
327 else if(spec_f->a < spec_t->a)
328 return false;
329
330 if(spec_f->b > spec_t->b)
331 return true;
332 else if(spec_f->b < spec_t->b)
333 return false;
334
335 if(spec_f->c > spec_t->c)
336 return true;
337 else if(spec_f->c < spec_t->c)
338 return false;
339
340 /* when a property is repeated with multiple values take the last one*/
341 return true;
342 }
343
modest_finder_thread_declaratin_append(modest_finder_thread_found_context_t * found_context,bool is_low_priority,modest_finder_thread_entry_t * entry,mycss_declaration_entry_t * dec_entry,modest_style_raw_specificity_t * raw_spec)344 void modest_finder_thread_declaratin_append(modest_finder_thread_found_context_t* found_context, bool is_low_priority,
345 modest_finder_thread_entry_t* entry, mycss_declaration_entry_t* dec_entry,
346 modest_style_raw_specificity_t* raw_spec)
347 {
348 if(entry->declaration == NULL) {
349 entry->declaration = entry->declaration_last = mcobject_async_malloc(found_context->finder_thread->declaration_obj,
350 found_context->context->declaration_node_id, NULL);
351
352 entry->declaration->entry = dec_entry;
353 entry->declaration->raw_spec = *raw_spec;
354 entry->declaration->next = NULL;
355 entry->declaration->prev = NULL;
356
357 return;
358 }
359
360 modest_finder_thread_declaration_t* thr_dec = entry->declaration;
361
362 while(thr_dec) {
363 if(thr_dec->entry->type == dec_entry->type)
364 {
365 if(modest_finder_thread_spec_is_up(raw_spec, &thr_dec->raw_spec)) {
366 thr_dec->entry = dec_entry;
367 thr_dec->raw_spec = *raw_spec;
368 }
369
370 return;
371 }
372
373 thr_dec = thr_dec->next;
374 }
375
376 thr_dec = mcobject_async_malloc(found_context->finder_thread->declaration_obj,
377 found_context->context->declaration_node_id, NULL);
378
379 thr_dec->next = NULL;
380 thr_dec->entry = dec_entry;
381 thr_dec->raw_spec = *raw_spec;
382
383 entry->declaration_last->next = thr_dec;
384 thr_dec->prev = entry->declaration_last;
385
386 entry->declaration_last = thr_dec;
387 }
388
modest_finder_thread_declaratin_list_replace(modest_finder_thread_found_context_t * found_context,modest_finder_thread_entry_t * entry,mycss_declaration_entry_t * dec_entry,mycss_selectors_specificity_t * spec)389 void modest_finder_thread_declaratin_list_replace(modest_finder_thread_found_context_t* found_context,
390 modest_finder_thread_entry_t* entry, mycss_declaration_entry_t* dec_entry,
391 mycss_selectors_specificity_t* spec)
392 {
393 while(dec_entry) {
394 modest_style_raw_specificity_t raw_spec = {((unsigned int)dec_entry->is_important), spec->a, spec->b, spec->c};
395
396 modest_finder_thread_declaratin_append(found_context, false, entry, dec_entry, &raw_spec);
397
398 dec_entry = dec_entry->next;
399 }
400 }
401
modest_finder_thread_callback_found(modest_finder_t * finder,myhtml_tree_node_t * node,mycss_selectors_list_t * selector_list,mycss_selectors_entry_t * selector,mycss_selectors_specificity_t * spec,void * ctx)402 void modest_finder_thread_callback_found(modest_finder_t* finder, myhtml_tree_node_t* node, mycss_selectors_list_t* selector_list, mycss_selectors_entry_t* selector, mycss_selectors_specificity_t* spec, void* ctx)
403 {
404 modest_finder_thread_found_context_t* found_context = (modest_finder_thread_found_context_t*)ctx;
405 modest_finder_thread_context_t* thread_context = found_context->context;
406
407 if(thread_context->entry_last) {
408 modest_finder_thread_entry_t* entry = thread_context->entry;
409
410 while(entry)
411 {
412 if(entry->node == node) {
413 modest_finder_thread_declaratin_list_replace(found_context, entry, selector_list->declaration_entry, spec);
414 return;
415 }
416
417 entry = entry->next;
418 }
419 }
420
421 modest_finder_thread_entry_t* entry = mcobject_async_malloc(found_context->finder_thread->entry_obj, thread_context->entry_node_id, NULL);
422 memset(entry, 0, sizeof(modest_finder_thread_entry_t));
423
424 entry->node = node;
425
426 modest_finder_thread_declaratin_list_replace(found_context, entry, selector_list->declaration_entry, spec);
427
428 if(thread_context->entry_last) {
429 entry->prev = thread_context->entry_last;
430
431 thread_context->entry_last->next = entry;
432 thread_context->entry_last = entry;
433 }
434 else {
435 thread_context->entry_last = thread_context->entry = entry;
436 }
437 }
438
modest_finder_thread_stream_single(modest_finder_thread_t * finder_thread,mycss_selectors_list_t * selector_list)439 void modest_finder_thread_stream_single(modest_finder_thread_t* finder_thread, mycss_selectors_list_t* selector_list)
440 {
441 modest_finder_thread_found_context_t found_ctx = {finder_thread, finder_thread->context_list};
442
443 while(selector_list)
444 {
445 for(size_t i = 0; i < selector_list->entries_list_length; i++) {
446 mycss_selectors_entries_list_t *entries = &selector_list->entries_list[i];
447 mycss_selectors_specificity_t spec = entries->specificity;
448
449 modest_finder_node_combinator_begin(finder_thread->finder, finder_thread->base_node, selector_list,
450 entries->entry, &spec, modest_finder_thread_callback_found, &found_ctx);
451 }
452
453 selector_list = selector_list->next;
454 }
455 }
456
457 #ifndef MyCORE_BUILD_WITHOUT_THREADS
modest_finder_thread_stream(mythread_id_t thread_id,void * arg)458 void modest_finder_thread_stream(mythread_id_t thread_id, void* arg)
459 {
460 mythread_context_t* ctx = (mythread_context_t*)arg;
461 modest_finder_thread_t* finder_thread = (modest_finder_thread_t*)ctx->mythread->context;
462 mycss_selectors_list_t* selector_list = finder_thread->selector_list;
463
464 modest_finder_thread_found_context_t found_ctx = {finder_thread, &finder_thread->context_list[ctx->id]};
465
466 size_t count = 0, counnt_done = ctx->id - 1;
467 size_t offset = (ctx->mythread->entries_size - 1);
468
469 while(selector_list) {
470 for(size_t i = 0; i < selector_list->entries_list_length; i++) {
471 /* split selectors by thread id */
472 if(count == counnt_done) {
473 mycss_selectors_entries_list_t *entries = &selector_list->entries_list[i];
474 mycss_selectors_specificity_t spec = entries->specificity;
475
476 modest_finder_node_combinator_begin(finder_thread->finder, finder_thread->base_node, selector_list,
477 entries->entry, &spec, modest_finder_thread_callback_found, &found_ctx);
478
479 counnt_done += offset;
480 }
481
482 count++;
483 }
484
485 selector_list = selector_list->next;
486 }
487 }
488 #endif
489
490