aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/evas/src/lib/cache/evas_cache_image.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libraries/evas/src/lib/cache/evas_cache_image.c1433
1 files changed, 1433 insertions, 0 deletions
diff --git a/libraries/evas/src/lib/cache/evas_cache_image.c b/libraries/evas/src/lib/cache/evas_cache_image.c
new file mode 100644
index 0000000..d52c64e
--- /dev/null
+++ b/libraries/evas/src/lib/cache/evas_cache_image.c
@@ -0,0 +1,1433 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <stdlib.h>
6#include <assert.h>
7#include <sys/types.h>
8#include <sys/stat.h>
9#include <errno.h>
10
11#ifdef HAVE_EVIL
12# include <Evil.h>
13#endif
14
15#include "evas_common.h"
16#include "evas_private.h"
17
18//#define CACHEDUMP 1
19
20#ifdef EVAS_CSERVE
21// FIXME: cache server and threaded preload clash badly atm - disable
22//#undef BUILD_ASYNC_PRELOAD
23#endif
24
25#ifdef BUILD_ASYNC_PRELOAD
26typedef struct _Evas_Cache_Preload Evas_Cache_Preload;
27
28struct _Evas_Cache_Preload
29{
30 EINA_INLIST;
31 Image_Entry *ie;
32};
33
34static LK(engine_lock);
35static LK(wakeup);
36static int _evas_cache_mutex_init = 0;
37
38static Eina_Condition cond_wakeup;
39
40static void _evas_cache_image_entry_preload_remove(Image_Entry *ie, const void *target);
41#endif
42
43#define FREESTRC(Var) \
44 if (Var) \
45 { \
46 eina_stringshare_del(Var); \
47 Var = NULL; \
48 }
49
50static void _evas_cache_image_dirty_add(Image_Entry *im);
51static void _evas_cache_image_dirty_del(Image_Entry *im);
52static void _evas_cache_image_activ_add(Image_Entry *im);
53static void _evas_cache_image_activ_del(Image_Entry *im);
54static void _evas_cache_image_lru_add(Image_Entry *im);
55static void _evas_cache_image_lru_del(Image_Entry *im);
56static void _evas_cache_image_lru_nodata_add(Image_Entry *im);
57static void _evas_cache_image_lru_nodata_del(Image_Entry *im);
58
59static void
60_evas_cache_image_dirty_add(Image_Entry *im)
61{
62 if (im->flags.dirty) return;
63 _evas_cache_image_activ_del(im);
64 _evas_cache_image_lru_del(im);
65 _evas_cache_image_lru_nodata_del(im);
66 im->flags.dirty = 1;
67 im->flags.cached = 1;
68#ifdef EVAS_FRAME_QUEUING
69 LKL(im->cache->lock);
70#endif
71 im->cache->dirty = eina_inlist_prepend(im->cache->dirty, EINA_INLIST_GET(im));
72#ifdef EVAS_FRAME_QUEUING
73 LKU(im->cache->lock);
74#endif
75 if (im->cache_key)
76 {
77 eina_stringshare_del(im->cache_key);
78 im->cache_key = NULL;
79 }
80}
81
82static void
83_evas_cache_image_dirty_del(Image_Entry *im)
84{
85 if (!im->flags.dirty) return;
86 im->flags.dirty = 0;
87 im->flags.cached = 0;
88#ifdef EVAS_FRAME_QUEUING
89 LKL(im->cache->lock);
90#endif
91 im->cache->dirty = eina_inlist_remove(im->cache->dirty, EINA_INLIST_GET(im));
92#ifdef EVAS_FRAME_QUEUING
93 LKU(im->cache->lock);
94#endif
95}
96
97static void
98_evas_cache_image_activ_add(Image_Entry *im)
99{
100 if (im->flags.activ) return;
101 _evas_cache_image_dirty_del(im);
102 _evas_cache_image_lru_del(im);
103 _evas_cache_image_lru_nodata_del(im);
104 if (!im->cache_key) return;
105 im->flags.activ = 1;
106 im->flags.cached = 1;
107#ifdef EVAS_FRAME_QUEUING
108 LKL(im->cache->lock);
109#endif
110 eina_hash_direct_add(im->cache->activ, im->cache_key, im);
111#ifdef EVAS_FRAME_QUEUING
112 LKU(im->cache->lock);
113#endif
114}
115
116static void
117_evas_cache_image_activ_del(Image_Entry *im)
118{
119 if (!im->flags.activ) return;
120 if (!im->cache_key) return;
121 im->flags.activ = 0;
122 im->flags.cached = 0;
123#ifdef EVAS_FRAME_QUEUING
124 LKL(im->cache->lock);
125#endif
126 eina_hash_del(im->cache->activ, im->cache_key, im);
127#ifdef EVAS_FRAME_QUEUING
128 LKU(im->cache->lock);
129#endif
130}
131
132static void
133_evas_cache_image_lru_add(Image_Entry *im)
134{
135 if (im->flags.lru) return;
136 _evas_cache_image_dirty_del(im);
137 _evas_cache_image_activ_del(im);
138 _evas_cache_image_lru_nodata_del(im);
139 if (!im->cache_key) return;
140 im->flags.lru = 1;
141 im->flags.cached = 1;
142#ifdef EVAS_FRAME_QUEUING
143 LKL(im->cache->lock);
144#endif
145 eina_hash_direct_add(im->cache->inactiv, im->cache_key, im);
146 im->cache->lru = eina_inlist_prepend(im->cache->lru, EINA_INLIST_GET(im));
147 im->cache->usage += im->cache->func.mem_size_get(im);
148#ifdef EVAS_FRAME_QUEUING
149 LKU(im->cache->lock);
150#endif
151}
152
153static void
154_evas_cache_image_lru_del(Image_Entry *im)
155{
156 if (!im->flags.lru) return;
157 if (!im->cache_key) return;
158 im->flags.lru = 0;
159 im->flags.cached = 0;
160#ifdef EVAS_FRAME_QUEUING
161 LKL(im->cache->lock);
162#endif
163 eina_hash_del(im->cache->inactiv, im->cache_key, im);
164 im->cache->lru = eina_inlist_remove(im->cache->lru, EINA_INLIST_GET(im));
165 im->cache->usage -= im->cache->func.mem_size_get(im);
166#ifdef EVAS_FRAME_QUEUING
167 LKU(im->cache->lock);
168#endif
169}
170
171static void
172_evas_cache_image_lru_nodata_add(Image_Entry *im)
173{
174 if (im->flags.lru_nodata) return;
175 _evas_cache_image_dirty_del(im);
176 _evas_cache_image_activ_del(im);
177 _evas_cache_image_lru_del(im);
178 im->flags.lru = 1;
179 im->flags.cached = 1;
180#ifdef EVAS_FRAME_QUEUING
181 LKL(im->cache->lock);
182#endif
183 im->cache->lru_nodata = eina_inlist_prepend(im->cache->lru_nodata, EINA_INLIST_GET(im));
184#ifdef EVAS_FRAME_QUEUING
185 LKU(im->cache->lock);
186#endif
187}
188
189static void
190_evas_cache_image_lru_nodata_del(Image_Entry *im)
191{
192 if (!im->flags.lru_nodata) return;
193 im->flags.lru = 0;
194 im->flags.cached = 0;
195#ifdef EVAS_FRAME_QUEUING
196 LKL(im->cache->lock);
197#endif
198 im->cache->lru_nodata = eina_inlist_remove(im->cache->lru_nodata, EINA_INLIST_GET(im));
199#ifdef EVAS_FRAME_QUEUING
200 LKU(im->cache->lock);
201#endif
202}
203
204static void
205_evas_cache_image_entry_delete(Evas_Cache_Image *cache, Image_Entry *ie)
206{
207 if (!ie) return;
208 if (cache->func.debug) cache->func.debug("deleting", ie);
209#ifdef BUILD_ASYNC_PRELOAD
210 if (ie->flags.delete_me == 1) return;
211 if (ie->preload)
212 {
213 ie->flags.delete_me = 1;
214 _evas_cache_image_entry_preload_remove(ie, NULL);
215 return;
216 }
217#endif
218
219 _evas_cache_image_dirty_del(ie);
220 _evas_cache_image_activ_del(ie);
221 _evas_cache_image_lru_del(ie);
222 _evas_cache_image_lru_nodata_del(ie);
223
224 cache->func.destructor(ie);
225 FREESTRC(ie->cache_key);
226 FREESTRC(ie->file);
227 FREESTRC(ie->key);
228 ie->cache = NULL;
229 cache->func.surface_delete(ie);
230
231#ifdef BUILD_ASYNC_PRELOAD
232 LKD(ie->lock);
233 LKD(ie->lock_cancel);
234#endif
235#ifdef EVAS_FRAME_QUEUING
236 LKD(ie->lock_references);
237#endif
238 cache->func.dealloc(ie);
239}
240
241static Eina_Bool
242_timestamp_compare(Image_Timestamp *tstamp, struct stat *st)
243{
244 if (tstamp->mtime != st->st_mtime) return EINA_FALSE;
245 if (tstamp->size != st->st_size) return EINA_FALSE;
246 if (tstamp->ino != st->st_ino) return EINA_FALSE;
247#ifdef _STAT_VER_LINUX
248#if (defined __USE_MISC && defined st_mtime)
249 if (tstamp->mtime_nsec != (unsigned long int)st->st_mtim.tv_nsec)
250 return EINA_FALSE;
251#else
252 if (tstamp->mtime_nsec != (unsigned long int)st->st_mtimensec)
253 return EINA_FALSE;
254#endif
255#endif
256 return EINA_TRUE;
257}
258
259static void
260_timestamp_build(Image_Timestamp *tstamp, struct stat *st)
261{
262 tstamp->mtime = st->st_mtime;
263 tstamp->size = st->st_size;
264 tstamp->ino = st->st_ino;
265#ifdef _STAT_VER_LINUX
266#if (defined __USE_MISC && defined st_mtime)
267 tstamp->mtime_nsec = (unsigned long int)st->st_mtim.tv_nsec;
268#else
269 tstamp->mtime_nsec = (unsigned long int)st->st_mtimensec;
270#endif
271#endif
272}
273
274static Image_Entry *
275_evas_cache_image_entry_new(Evas_Cache_Image *cache,
276 const char *hkey,
277 Image_Timestamp *tstamp,
278 const char *file,
279 const char *key,
280 RGBA_Image_Loadopts *lo,
281 int *error)
282{
283 Image_Entry *ie;
284
285 ie = cache->func.alloc();
286 if (!ie)
287 {
288 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
289 return NULL;
290 }
291 ie->cache = cache;
292 if (hkey) ie->cache_key = eina_stringshare_add(hkey);
293 ie->flags.need_data = 1;
294 ie->space = EVAS_COLORSPACE_ARGB8888;
295 ie->w = -1;
296 ie->h = -1;
297 ie->scale = 1;
298 if (file) ie->file = eina_stringshare_add(file);
299 if (key) ie->key = eina_stringshare_add(key);
300 if (tstamp) ie->tstamp = *tstamp;
301 else memset(&ie->tstamp, 0, sizeof(Image_Timestamp));
302
303#ifdef EVAS_FRAME_QUEUING
304 LKI(ie->lock_references);
305#endif
306#ifdef BUILD_ASYNC_PRELOAD
307 LKI(ie->lock);
308 LKI(ie->lock_cancel);
309#endif
310
311 if (lo) ie->load_opts = *lo;
312 if (ie->file)
313 {
314 *error = cache->func.constructor(ie);
315 if (*error != EVAS_LOAD_ERROR_NONE)
316 {
317 _evas_cache_image_entry_delete(cache, ie);
318 return NULL;
319 }
320 }
321 if (cache->func.debug) cache->func.debug("build", ie);
322 if (ie->cache_key) _evas_cache_image_activ_add(ie);
323 else _evas_cache_image_dirty_add(ie);
324 return ie;
325}
326
327static void
328_evas_cache_image_entry_surface_alloc__locked(Evas_Cache_Image *cache,
329 Image_Entry *ie,
330 unsigned int wmin,
331 unsigned int hmin)
332{
333 if ((ie->allocated.w == wmin) && (ie->allocated.h == hmin)) return;
334 if (cache->func.surface_alloc(ie, wmin, hmin))
335 {
336 wmin = 0;
337 hmin = 0;
338 }
339 ie->w = wmin;
340 ie->h = hmin;
341 ie->allocated.w = wmin;
342 ie->allocated.h = hmin;
343}
344
345static void
346_evas_cache_image_entry_surface_alloc(Evas_Cache_Image *cache,
347 Image_Entry *ie, int w, int h)
348{
349 int wmin = w > 0 ? w : 1;
350 int hmin = h > 0 ? h : 1;
351#ifdef BUILD_ASYNC_PRELOAD
352 LKL(engine_lock);
353#endif
354 _evas_cache_image_entry_surface_alloc__locked(cache, ie, wmin, hmin);
355#ifdef BUILD_ASYNC_PRELOAD
356 LKU(engine_lock);
357#endif
358}
359
360#ifdef BUILD_ASYNC_PRELOAD
361static void
362_evas_cache_image_async_heavy(void *data)
363{
364 Evas_Cache_Image *cache;
365 Image_Entry *current;
366 int error;
367 int pchannel;
368
369 current = data;
370
371 LKL(current->lock);
372 pchannel = current->channel;
373 current->channel++;
374 cache = current->cache;
375
376 if ((!current->flags.loaded) &&
377 ((Evas_Image_Load_Func*) current->info.module)->threadable)
378 {
379 error = cache->func.load(current);
380 if (cache->func.debug) cache->func.debug("load", current);
381 current->load_error = error;
382 if (error != EVAS_LOAD_ERROR_NONE)
383 {
384 current->flags.loaded = 0;
385 _evas_cache_image_entry_surface_alloc(cache, current,
386 current->w, current->h);
387 }
388 else
389 {
390 current->flags.loaded = 1;
391 }
392 }
393 current->channel = pchannel;
394 // check the unload cancel flag
395 LKL(current->lock_cancel);
396 if (current->unload_cancel)
397 {
398 current->unload_cancel = EINA_FALSE;
399 cache->func.surface_delete(current);
400 current->flags.loaded = 0;
401 current->flags.preload_done = 0;
402 }
403 LKU(current->lock_cancel);
404 LKU(current->lock);
405}
406
407static void
408_evas_cache_image_async_end(void *data)
409{
410 Image_Entry *ie = (Image_Entry *)data;
411 Evas_Cache_Target *tmp;
412
413 ie->cache->preload = eina_list_remove(ie->cache->preload, ie);
414 ie->cache->pending = eina_list_remove(ie->cache->pending, ie);
415 ie->preload = NULL;
416 ie->flags.preload_done = ie->flags.loaded;
417 while ((tmp = ie->targets))
418 {
419 evas_object_inform_call_image_preloaded((Evas_Object*) tmp->target);
420 ie->targets = (Evas_Cache_Target *)
421 eina_inlist_remove(EINA_INLIST_GET(ie->targets),
422 EINA_INLIST_GET(ie->targets));
423 free(tmp);
424 }
425}
426
427static void
428_evas_cache_image_async_cancel(void *data)
429{
430 Evas_Cache_Image *cache = NULL;
431 Image_Entry *ie = (Image_Entry *)data;
432
433 ie->preload = NULL;
434 ie->cache->pending = eina_list_remove(ie->cache->pending, ie);
435 if ((ie->flags.delete_me) || (ie->flags.dirty))
436 {
437 ie->flags.delete_me = 0;
438 _evas_cache_image_entry_delete(ie->cache, ie);
439 return;
440 }
441 if (ie->flags.loaded) _evas_cache_image_async_end(ie);
442#ifdef EVAS_FRAME_QUEUING
443 LKL(ie->lock_references);
444#endif
445 if (ie->references == 0)
446 {
447 _evas_cache_image_lru_add(ie);
448 cache = ie->cache;
449 }
450#ifdef EVAS_FRAME_QUEUING
451 LKU(ie->lock_references);
452#endif
453 if (cache) evas_cache_image_flush(cache);
454}
455
456// note - preload_add assumes a target is ONLY added ONCE to the image
457// entry. make sure you only add once, or remove first, then add
458static int
459_evas_cache_image_entry_preload_add(Image_Entry *ie, const void *target)
460{
461 Evas_Cache_Target *tg;
462
463 if (ie->flags.preload_done) return 0;
464
465 tg = malloc(sizeof (Evas_Cache_Target));
466 if (!tg) return 0;
467
468 tg->target = target;
469 ie->targets = (Evas_Cache_Target *)
470 eina_inlist_append(EINA_INLIST_GET(ie->targets), EINA_INLIST_GET(tg));
471 if (!ie->preload)
472 {
473 ie->cache->preload = eina_list_append(ie->cache->preload, ie);
474 ie->flags.pending = 0;
475 ie->preload = evas_preload_thread_run(_evas_cache_image_async_heavy,
476 _evas_cache_image_async_end,
477 _evas_cache_image_async_cancel,
478 ie);
479 }
480 return 1;
481}
482
483static void
484_evas_cache_image_entry_preload_remove(Image_Entry *ie, const void *target)
485{
486 if (target)
487 {
488 Evas_Cache_Target *tg;
489
490 EINA_INLIST_FOREACH(ie->targets, tg)
491 {
492 if (tg->target == target)
493 {
494 // FIXME: No callback when we cancel only for one target ?
495 ie->targets = (Evas_Cache_Target *)
496 eina_inlist_remove(EINA_INLIST_GET(ie->targets),
497 EINA_INLIST_GET(tg));
498 free(tg);
499 break;
500 }
501 }
502 }
503 else
504 {
505 Evas_Cache_Target *tg;
506
507 while (ie->targets)
508 {
509 tg = ie->targets;
510 ie->targets = (Evas_Cache_Target *)
511 eina_inlist_remove(EINA_INLIST_GET(ie->targets),
512 EINA_INLIST_GET(tg));
513 free(tg);
514 }
515 }
516
517 if ((!ie->targets) && (ie->preload) && (!ie->flags.pending))
518 {
519 ie->cache->preload = eina_list_remove(ie->cache->preload, ie);
520 ie->cache->pending = eina_list_append(ie->cache->pending, ie);
521 ie->flags.pending = 1;
522 evas_preload_thread_cancel(ie->preload);
523 }
524}
525#endif
526
527EAPI int
528evas_cache_image_usage_get(Evas_Cache_Image *cache)
529{
530 return cache->usage;
531}
532
533EAPI int
534evas_cache_image_get(Evas_Cache_Image *cache)
535{
536 return cache->limit;
537}
538
539EAPI void
540evas_cache_image_set(Evas_Cache_Image *cache, unsigned int limit)
541{
542#ifdef EVAS_FRAME_QUEUING
543 LKL(cache->lock);
544#endif
545 if (cache->limit == limit)
546 {
547#ifdef EVAS_FRAME_QUEUING
548 LKU(cache->lock);
549#endif
550 return;
551 }
552 cache->limit = limit;
553#ifdef EVAS_FRAME_QUEUING
554 LKU(cache->lock);
555#endif
556 evas_cache_image_flush(cache);
557}
558
559EAPI Evas_Cache_Image *
560evas_cache_image_init(const Evas_Cache_Image_Func *cb)
561{
562 Evas_Cache_Image *cache;
563
564#ifdef BUILD_ASYNC_PRELOAD
565 if (_evas_cache_mutex_init++ == 0)
566 {
567 LKI(engine_lock);
568 LKI(wakeup);
569 eina_condition_new(&cond_wakeup, &wakeup);
570 }
571#endif
572
573 cache = calloc(1, sizeof(Evas_Cache_Image));
574 if (!cache) return NULL;
575 cache->func = *cb;
576 cache->inactiv = eina_hash_string_superfast_new(NULL);
577 cache->activ = eina_hash_string_superfast_new(NULL);
578 cache->references = 1;
579#ifdef EVAS_FRAME_QUEUING
580 LKI(cache->lock);
581#endif
582 return cache;
583}
584
585static Eina_Bool
586_evas_cache_image_free_cb(__UNUSED__ const Eina_Hash *hash, __UNUSED__ const void *key, void *data, void *fdata)
587{
588 Eina_List **delete_list = fdata;
589 *delete_list = eina_list_prepend(*delete_list, data);
590 return EINA_TRUE;
591}
592
593EAPI void
594evas_cache_image_shutdown(Evas_Cache_Image *cache)
595{
596 Eina_List *delete_list;
597 Image_Entry *im;
598
599#ifdef EVAS_FRAME_QUEUING
600 LKL(cache->lock);
601#endif
602 cache->references--;
603 if (cache->references != 0)
604 {
605#ifdef EVAS_FRAME_QUEUING
606 LKU(cache->lock);
607#endif
608 return;
609 }
610#ifdef EVAS_FRAME_QUEUING
611 /* Release and destroy lock early ! */
612 LKU(cache->lock);
613 LKD(cache->lock);
614#endif
615
616#ifdef BUILD_ASYNC_PRELOAD
617 EINA_LIST_FREE(cache->preload, im)
618 {
619 /* By doing that we are protecting us from destroying image when the cache is no longer available. */
620 im->flags.delete_me = 1;
621 _evas_cache_image_entry_preload_remove(im, NULL);
622 }
623 evas_async_events_process();
624#endif
625 while (cache->lru)
626 {
627 im = (Image_Entry *)cache->lru;
628 _evas_cache_image_entry_delete(cache, im);
629 }
630 while (cache->lru_nodata)
631 {
632 im = (Image_Entry *)cache->lru_nodata;
633 _evas_cache_image_entry_delete(cache, im);
634 }
635 /* This is mad, I am about to destroy image still alive, but we need to prevent leak. */
636 while (cache->dirty)
637 {
638 im = (Image_Entry *)cache->dirty;
639 _evas_cache_image_entry_delete(cache, im);
640 }
641 delete_list = NULL;
642 eina_hash_foreach(cache->activ, _evas_cache_image_free_cb, &delete_list);
643 while (delete_list)
644 {
645 _evas_cache_image_entry_delete(cache, eina_list_data_get(delete_list));
646 delete_list = eina_list_remove_list(delete_list, delete_list);
647 }
648
649#ifdef BUILD_ASYNC_PRELOAD
650 /* Now wait for all pending image to die */
651 while (cache->pending)
652 {
653 evas_async_events_process();
654 LKL(wakeup);
655 // the lazy bum who did eain threads and converted this code
656 // didn't bother to worry about Eina_Lock being a different type
657 // to a pthread mutex.
658 if (cache->pending) eina_condition_wait(&cond_wakeup);
659 LKU(wakeup);
660 }
661#endif
662 eina_hash_free(cache->activ);
663 eina_hash_free(cache->inactiv);
664 free(cache);
665
666#ifdef BUILD_ASYNC_PRELOAD
667 if (--_evas_cache_mutex_init == 0)
668 {
669 eina_condition_free(&cond_wakeup);
670 LKD(engine_lock);
671 LKD(wakeup);
672 }
673#endif
674}
675
676EAPI Image_Entry *
677evas_cache_image_request(Evas_Cache_Image *cache, const char *file,
678 const char *key, RGBA_Image_Loadopts *lo, int *error)
679{
680 const char *ckey = "(null)";
681 char *hkey;
682 Image_Entry *im;
683 Evas_Image_Load_Opts prevent = { 0, 0.0, 0, 0, 0, { 0, 0, 0, 0 }, EINA_FALSE };
684 size_t size;
685 int stat_done = 0, stat_failed = 0;
686 size_t file_length;
687 size_t key_length;
688 struct stat st;
689 Image_Timestamp tstamp;
690
691 if ((!file) || ((!file) && (!key)))
692 {
693 *error = EVAS_LOAD_ERROR_GENERIC;
694 return NULL;
695 }
696
697 /* generate hkey from file+key+load opts */
698 file_length = strlen(file);
699 key_length = key ? strlen(key) : 6;
700 size = file_length + key_length + 132;
701 hkey = alloca(sizeof (char) * size);
702 memcpy(hkey, file, file_length);
703 size = file_length;
704 memcpy(hkey + size, "//://", 5);
705 size += 5;
706 if (key) ckey = key;
707 memcpy(hkey + size, ckey, key_length);
708 size += key_length;
709 if ((!lo) ||
710 (lo &&
711 (lo->scale_down_by == 0) &&
712 (lo->dpi == 0.0) &&
713 ((lo->w == 0) || (lo->h == 0)) &&
714 ((lo->region.w == 0) || (lo->region.h == 0)) &&
715 (lo->orientation == 0)
716 ))
717 {
718 lo = &prevent;
719 }
720 else
721 {
722 memcpy(hkey + size, "//@/", 4);
723 size += 4;
724 size += eina_convert_xtoa(lo->scale_down_by, hkey + size);
725 hkey[size] = '/';
726 size += 1;
727 size += eina_convert_dtoa(lo->dpi, hkey + size);
728 hkey[size] = '/';
729 size += 1;
730 size += eina_convert_xtoa(lo->w, hkey + size);
731 hkey[size] = 'x';
732 size += 1;
733 size += eina_convert_xtoa(lo->h, hkey + size);
734 hkey[size] = '/';
735 size += 1;
736 size += eina_convert_xtoa(lo->region.x, hkey + size);
737 hkey[size] = '+';
738 size += 1;
739 size += eina_convert_xtoa(lo->region.y, hkey + size);
740 hkey[size] = '.';
741 size += 1;
742 size += eina_convert_xtoa(lo->region.w, hkey + size);
743 hkey[size] = 'x';
744 size += 1;
745 size += eina_convert_xtoa(lo->region.h, hkey + size);
746
747 if (lo->orientation)
748 {
749 hkey[size] = '/';
750 size += 1;
751 hkey[size] = 'o';
752 size += 1;
753 }
754 }
755 hkey[size] = '\0';
756
757 /* find image by key in active hash */
758#ifdef EVAS_FRAME_QUEUING
759 LKL(cache->lock);
760#endif
761 im = eina_hash_find(cache->activ, hkey);
762#ifdef EVAS_FRAME_QUEUING
763 LKU(cache->lock);
764#endif
765 if (im)
766 {
767 int ok = 1;
768
769 stat_done = 1;
770 if (stat(file, &st) < 0)
771 {
772 stat_failed = 1;
773 ok = 0;
774 }
775 else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
776 if (ok) goto on_ok;
777 /* image we found doesn't match what's on disk (stat info wise)
778 * so dirty the active cache entry so we never find it again. this
779 * also implicitly guarantees that we only have 1 active copy
780 * of an image at a given key. we wither find it and keep re-reffing
781 * it or we dirty it and get it out */
782 _evas_cache_image_dirty_add(im);
783 im = NULL;
784 }
785
786 /* find image by key in inactive/lru hash */
787#ifdef EVAS_FRAME_QUEUING
788 LKL(cache->lock);
789#endif
790 im = eina_hash_find(cache->inactiv, hkey);
791#ifdef EVAS_FRAME_QUEUING
792 LKU(cache->lock);
793#endif
794 if (im)
795 {
796 int ok = 1;
797
798 if (!stat_done)
799 {
800 stat_done = 1;
801 if (stat(file, &st) < 0)
802 {
803 stat_failed = 1;
804 ok = 0;
805 }
806 else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
807 }
808 else if (!_timestamp_compare(&(im->tstamp), &st)) ok = 0;
809
810 if (ok)
811 {
812 /* remove from lru and make it active again */
813 _evas_cache_image_lru_del(im);
814 _evas_cache_image_activ_add(im);
815 goto on_ok;
816 }
817 /* as avtive cache find - if we match in lru and its invalid, dirty */
818 _evas_cache_image_dirty_add(im);
819 im = NULL;
820 }
821 if (stat_failed) goto on_stat_error;
822
823 if (!stat_done)
824 {
825 if (stat(file, &st) < 0) goto on_stat_error;
826 }
827 _timestamp_build(&tstamp, &st);
828 im = _evas_cache_image_entry_new(cache, hkey, &tstamp, file, key,
829 lo, error);
830 if (!im) goto on_stat_error;
831 if (cache->func.debug) cache->func.debug("request", im);
832
833 on_ok:
834 *error = EVAS_LOAD_ERROR_NONE;
835#ifdef EVAS_FRAME_QUEUING
836 LKL(im->lock_references);
837#endif
838 im->references++;
839#ifdef EVAS_FRAME_QUEUING
840 LKU(im->lock_references);
841#endif
842 return im;
843
844 on_stat_error:
845#ifndef _WIN32
846 if ((errno == ENOENT) || (errno == ENOTDIR) ||
847 (errno == ENAMETOOLONG) || (errno == ELOOP))
848#else
849 if (errno == ENOENT)
850#endif
851 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
852#ifndef _WIN32
853 else if ((errno == ENOMEM) || (errno == EOVERFLOW))
854#else
855 else if (errno == ENOMEM)
856#endif
857 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
858 else if (errno == EACCES)
859 *error = EVAS_LOAD_ERROR_PERMISSION_DENIED;
860 else
861 *error = EVAS_LOAD_ERROR_GENERIC;
862
863 if (im) _evas_cache_image_entry_delete(cache, im);
864 return NULL;
865}
866
867EAPI void
868evas_cache_image_drop(Image_Entry *im)
869{
870 Evas_Cache_Image *cache;
871 int references;
872
873#ifdef EVAS_FRAME_QUEUING
874 LKL(im->lock_references);
875#endif
876 im->references--;
877 if (im->references < 0) im->references = 0;
878 references = im->references;
879#ifdef EVAS_FRAME_QUEUING
880 LKU(im->lock_references);
881#endif
882
883 cache = im->cache;
884
885 if (references == 0)
886 {
887#ifdef EVAS_FRAME_QUEUING
888 LKL(im->ref_fq_add);
889 LKL(im->ref_fq_del);
890 if (im->ref_fq[0] != im->ref_fq[1])
891 {
892 LKU(im->ref_fq_add);
893 LKU(im->ref_fq_del);
894 return;
895 }
896 LKU(im->ref_fq_add);
897 LKU(im->ref_fq_del);
898#endif
899
900#ifdef BUILD_ASYNC_PRELOAD
901 if (im->preload)
902 {
903 _evas_cache_image_entry_preload_remove(im, NULL);
904 return;
905 }
906#endif
907
908 if (im->flags.dirty)
909 {
910 _evas_cache_image_entry_delete(cache, im);
911 return;
912 }
913 _evas_cache_image_lru_add(im);
914 if (cache) evas_cache_image_flush(cache);
915 }
916}
917
918EAPI void
919evas_cache_image_data_not_needed(Image_Entry *im)
920{
921 Evas_Cache_Image *cache;
922 int references;
923
924 /* FIXME: no one uses this api... well evas_cache_engine_parent_not_needed()
925 * does, but nothing uses that! */
926 cache = im->cache;
927#ifdef EVAS_FRAME_QUEUING
928 LKL(im->lock_references);
929#endif
930 references = im->references;
931#ifdef EVAS_FRAME_QUEUING
932 LKU(im->lock_references);
933#endif
934 if (references > 1) return;
935 if ((im->flags.dirty) || (!im->flags.need_data)) return;
936 _evas_cache_image_lru_nodata_add(im);
937}
938
939EAPI Image_Entry *
940evas_cache_image_dirty(Image_Entry *im, unsigned int x, unsigned int y, unsigned int w, unsigned int h)
941{
942 Image_Entry *im_dirty = im;
943 Evas_Cache_Image *cache;
944 int references;
945
946 cache = im->cache;
947 if (!(im->flags.dirty))
948 {
949#ifdef EVAS_FRAME_QUEUING
950 LKL(im->lock_references);
951#endif
952 references = im->references;
953#ifdef EVAS_FRAME_QUEUING
954 LKU(im->lock_references);
955#endif
956#ifndef EVAS_CSERVE
957 // if ref 1 also copy if using shared cache as its read-only
958 if (references == 1) im_dirty = im;
959 else
960#endif
961 {
962 int error;
963
964 im_dirty =
965 evas_cache_image_copied_data(cache, im->w, im->h,
966 evas_cache_image_pixels(im),
967 im->flags.alpha, im->space);
968 if (!im_dirty) goto on_error;
969 if (cache->func.debug) cache->func.debug("dirty-src", im);
970 error = cache->func.dirty(im_dirty, im);
971 if (cache->func.debug) cache->func.debug("dirty-out", im_dirty);
972#ifdef EVAS_FRAME_QUEUING
973 LKL(im_dirty->lock_references);
974#endif
975 im_dirty->references = 1;
976#ifdef EVAS_FRAME_QUEUING
977 LKU(im_dirty->lock_references);
978#endif
979 evas_cache_image_drop(im);
980 }
981 _evas_cache_image_dirty_add(im_dirty);
982 }
983
984 if (cache->func.debug) cache->func.debug("dirty-region", im_dirty);
985 if (cache->func.dirty_region)
986 cache->func.dirty_region(im_dirty, x, y, w, h);
987 return im_dirty;
988
989on_error:
990 if (im_dirty) _evas_cache_image_entry_delete(cache, im_dirty);
991 evas_cache_image_drop(im);
992 return NULL;
993}
994
995EAPI Image_Entry *
996evas_cache_image_alone(Image_Entry *im)
997{
998 Evas_Cache_Image *cache;
999 Image_Entry *im_dirty = im;
1000 int references;
1001
1002 cache = im->cache;
1003#ifdef EVAS_FRAME_QUEUING
1004 LKL(im->lock_references);
1005#endif
1006 references = im->references;
1007#ifdef EVAS_FRAME_QUEUING
1008 LKU(im->lock_references);
1009#endif
1010
1011 if (references <= 1)
1012 {
1013 if (!im->flags.dirty) _evas_cache_image_dirty_add(im);
1014 }
1015 else
1016 {
1017 int error;
1018
1019 im_dirty = evas_cache_image_copied_data(cache, im->w, im->h,
1020 evas_cache_image_pixels(im),
1021 im->flags.alpha,
1022 im->space);
1023 if (!im_dirty) goto on_error;
1024 if (cache->func.debug) cache->func.debug("dirty-src", im);
1025 error = cache->func.dirty(im_dirty, im);
1026 if (cache->func.debug) cache->func.debug("dirty-out", im_dirty);
1027#ifdef EVAS_FRAME_QUEUING
1028 LKL(im_dirty->lock_references);
1029#endif
1030 im_dirty->references = 1;
1031#ifdef EVAS_FRAME_QUEUING
1032 LKU(im_dirty->lock_references);
1033#endif
1034 evas_cache_image_drop(im);
1035 }
1036 return im_dirty;
1037
1038on_error:
1039 if (im_dirty) _evas_cache_image_entry_delete(cache, im_dirty);
1040 evas_cache_image_drop(im);
1041 return NULL;
1042}
1043
1044EAPI Image_Entry *
1045evas_cache_image_copied_data(Evas_Cache_Image *cache,
1046 unsigned int w, unsigned int h,
1047 DATA32 *image_data, int alpha, int cspace)
1048{
1049 Image_Entry *im;
1050
1051 if ((cspace == EVAS_COLORSPACE_YCBCR422P601_PL) ||
1052 (cspace == EVAS_COLORSPACE_YCBCR422P709_PL) ||
1053 (cspace == EVAS_COLORSPACE_YCBCR422601_PL))
1054 w &= ~0x1;
1055
1056 im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
1057 if (!im) return NULL;
1058 im->space = cspace;
1059 im->flags.alpha = alpha;
1060 _evas_cache_image_entry_surface_alloc(cache, im, w, h);
1061 if (cache->func.copied_data(im, w, h, image_data, alpha, cspace) != 0)
1062 {
1063 _evas_cache_image_entry_delete(cache, im);
1064 return NULL;
1065 }
1066#ifdef EVAS_FRAME_QUEUING
1067 LKL(im->lock_references);
1068#endif
1069 im->references = 1;
1070#ifdef EVAS_FRAME_QUEUING
1071 LKU(im->lock_references);
1072#endif
1073 if (cache->func.debug) cache->func.debug("copied-data", im);
1074 return im;
1075}
1076
1077EAPI Image_Entry *
1078evas_cache_image_data(Evas_Cache_Image *cache, unsigned int w, unsigned int h, DATA32 *image_data, int alpha, int cspace)
1079{
1080 Image_Entry *im;
1081
1082 if ((cspace == EVAS_COLORSPACE_YCBCR422P601_PL) ||
1083 (cspace == EVAS_COLORSPACE_YCBCR422P709_PL) ||
1084 (cspace == EVAS_COLORSPACE_YCBCR422601_PL))
1085 w &= ~0x1;
1086
1087 im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
1088 if (!im) return NULL;
1089 im->w = w;
1090 im->h = h;
1091 im->flags.alpha = alpha;
1092 if (cache->func.data(im, w, h, image_data, alpha, cspace) != 0)
1093 {
1094 _evas_cache_image_entry_delete(cache, im);
1095 return NULL;
1096 }
1097#ifdef EVAS_FRAME_QUEUING
1098 LKL(im->lock_references);
1099#endif
1100 im->references = 1;
1101#ifdef EVAS_FRAME_QUEUING
1102 LKU(im->lock_references);
1103#endif
1104 if (cache->func.debug) cache->func.debug("data", im);
1105 return im;
1106}
1107
1108EAPI void
1109evas_cache_image_surface_alloc(Image_Entry *im, unsigned int w, unsigned int h)
1110{
1111 Evas_Cache_Image *cache = im->cache;
1112
1113 if ((im->space == EVAS_COLORSPACE_YCBCR422P601_PL) ||
1114 (im->space == EVAS_COLORSPACE_YCBCR422P709_PL) ||
1115 (im->space == EVAS_COLORSPACE_YCBCR422601_PL))
1116 w &= ~0x1;
1117
1118 _evas_cache_image_entry_surface_alloc(cache, im, w, h);
1119 if (cache->func.debug) cache->func.debug("surface-alloc", im);
1120}
1121
1122EAPI Image_Entry *
1123evas_cache_image_size_set(Image_Entry *im, unsigned int w, unsigned int h)
1124{
1125 Evas_Cache_Image *cache;
1126 Image_Entry *im2 = NULL;
1127 int error;
1128
1129 if ((im->space == EVAS_COLORSPACE_YCBCR422P601_PL) ||
1130 (im->space == EVAS_COLORSPACE_YCBCR422P709_PL) ||
1131 (im->space == EVAS_COLORSPACE_YCBCR422601_PL))
1132 w &= ~0x1;
1133 if ((im->w == w) && (im->h == h)) return im;
1134
1135 cache = im->cache;
1136 im2 = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, &error);
1137 if (!im2) goto on_error;
1138
1139 im2->flags.alpha = im->flags.alpha;
1140 im2->space = im->space;
1141 im2->load_opts = im->load_opts;
1142 _evas_cache_image_entry_surface_alloc(cache, im2, w, h);
1143 error = cache->func.size_set(im2, im, w, h);
1144 if (error != 0) goto on_error;
1145#ifdef EVAS_FRAME_QUEUING
1146 LKL(im2->lock_references);
1147#endif
1148 im2->references = 1;
1149#ifdef EVAS_FRAME_QUEUING
1150 LKU(im2->lock_references);
1151#endif
1152 evas_cache_image_drop(im);
1153 if (cache->func.debug) cache->func.debug("size_set", im2);
1154 return im2;
1155
1156 on_error:
1157 if (im2) _evas_cache_image_entry_delete(cache, im2);
1158 evas_cache_image_drop(im);
1159 return NULL;
1160}
1161
1162EAPI int
1163evas_cache_image_load_data(Image_Entry *im)
1164{
1165#ifdef BUILD_ASYNC_PRELOAD
1166 Eina_Bool preload = EINA_FALSE;
1167#endif
1168 int error = EVAS_LOAD_ERROR_NONE;
1169
1170 if ((im->flags.loaded) && (!im->flags.animated)) return error;
1171#ifdef BUILD_ASYNC_PRELOAD
1172 if (im->preload)
1173 {
1174 preload = EINA_TRUE;
1175 if (!im->flags.pending)
1176 {
1177 im->cache->preload = eina_list_remove(im->cache->preload, im);
1178 im->cache->pending = eina_list_append(im->cache->pending, im);
1179 im->flags.pending = 1;
1180 evas_preload_thread_cancel(im->preload);
1181 }
1182 evas_async_events_process();
1183 LKL(wakeup);
1184 while (im->preload)
1185 {
1186 eina_condition_wait(&cond_wakeup);
1187 LKU(wakeup);
1188 evas_async_events_process();
1189 LKL(wakeup);
1190 }
1191 LKU(wakeup);
1192 }
1193
1194 if ((im->flags.loaded) && (!im->flags.animated)) return error;
1195 LKL(im->lock);
1196#endif
1197 im->flags.in_progress = EINA_TRUE;
1198 error = im->cache->func.load(im);
1199 im->flags.in_progress = EINA_FALSE;
1200#ifdef BUILD_ASYNC_PRELOAD
1201 LKU(im->lock);
1202#endif
1203 im->flags.loaded = 1;
1204 if (im->cache->func.debug) im->cache->func.debug("load", im);
1205 if (error != EVAS_LOAD_ERROR_NONE)
1206 {
1207 _evas_cache_image_entry_surface_alloc(im->cache, im, im->w, im->h);
1208 im->flags.loaded = 0;
1209 }
1210#ifdef BUILD_ASYNC_PRELOAD
1211 if (preload) _evas_cache_image_async_end(im);
1212#endif
1213 return error;
1214}
1215
1216EAPI void
1217evas_cache_image_unload_data(Image_Entry *im)
1218{
1219 if (im->flags.in_progress) return;
1220 evas_cache_image_preload_cancel(im, NULL);
1221#ifdef BUILD_ASYNC_PRELOAD
1222 LKL(im->lock_cancel);
1223 if (LKT(im->lock) == EINA_FALSE) /* can't get image lock - busy async load */
1224 {
1225 im->unload_cancel = EINA_TRUE;
1226 LKU(im->lock_cancel);
1227 return;
1228 }
1229 LKU(im->lock_cancel);
1230#endif
1231 if ((!im->flags.loaded) || (!im->file) || (!im->info.module) ||
1232 (im->flags.dirty))
1233 {
1234#ifdef BUILD_ASYNC_PRELOAD
1235 LKU(im->lock);
1236#endif
1237 return;
1238 }
1239 im->cache->func.destructor(im);
1240#ifdef BUILD_ASYNC_PRELOAD
1241 LKU(im->lock);
1242#endif
1243 //FIXME: imagedataunload - inform owners
1244}
1245
1246static Eina_Bool
1247_evas_cache_image_unload_cb(__UNUSED__ const Eina_Hash *hash, __UNUSED__ const void *key, void *data, __UNUSED__ void *fdata)
1248{
1249 evas_cache_image_unload_data(data);
1250 return EINA_TRUE;
1251}
1252
1253EAPI void
1254evas_cache_image_unload_all(Evas_Cache_Image *cache)
1255{
1256 Image_Entry *im;
1257
1258 EINA_INLIST_FOREACH(cache->lru, im) evas_cache_image_unload_data(im);
1259 EINA_INLIST_FOREACH(cache->lru_nodata, im) evas_cache_image_unload_data(im);
1260 eina_hash_foreach(cache->activ, _evas_cache_image_unload_cb, NULL);
1261 eina_hash_foreach(cache->inactiv, _evas_cache_image_unload_cb, NULL);
1262}
1263
1264EAPI Eina_Bool
1265evas_cache_image_is_loaded(Image_Entry *im)
1266{
1267 if (im->flags.loaded) return EINA_TRUE;
1268 return EINA_FALSE;
1269}
1270
1271EAPI void
1272evas_cache_image_preload_data(Image_Entry *im, const void *target)
1273{
1274#ifdef BUILD_ASYNC_PRELOAD
1275 RGBA_Image *img = (RGBA_Image *)im;
1276
1277 if ((im->flags.loaded) && (img->image.data))
1278 {
1279 evas_object_inform_call_image_preloaded((Evas_Object *)target);
1280 return;
1281 }
1282 im->flags.loaded = 0;
1283 if (!_evas_cache_image_entry_preload_add(im, target))
1284 evas_object_inform_call_image_preloaded((Evas_Object *)target);
1285#else
1286 evas_cache_image_load_data(im);
1287 evas_object_inform_call_image_preloaded((Evas_Object *)target);
1288#endif
1289}
1290
1291EAPI void
1292evas_cache_image_preload_cancel(Image_Entry *im, const void *target)
1293{
1294#ifdef BUILD_ASYNC_PRELOAD
1295 if (!target) return;
1296 _evas_cache_image_entry_preload_remove(im, target);
1297#else
1298 (void)im;
1299#endif
1300}
1301
1302#ifdef CACHEDUMP
1303static int total = 0;
1304
1305static void
1306_dump_img(Image_Entry *im, const char *type)
1307{
1308 total += im->cache->func.mem_size_get(im);
1309 printf("%s: %4i: %4ib, %4ix%4i alloc[%4ix%4i] [%s] [%s]\n",
1310 type,
1311 im->references,
1312 im->cache->func.mem_size_get(im),
1313 im->w, im->h, im->allocated.w, im->allocated.h,
1314 im->file, im->key);
1315}
1316
1317static Eina_Bool
1318_dump_cache_active(__UNUSED__ const Eina_Hash *hash, __UNUSED__ const void *key, void *data, void *fdata __UNUSED__)
1319{
1320 Image_Entry *im = data;
1321 _dump_img(im, "ACTIVE");
1322 return EINA_TRUE;
1323}
1324
1325static void
1326_dump_cache(Evas_Cache_Image *cache)
1327{
1328 Image_Entry *im;
1329
1330 printf("--CACHE DUMP----------------------------------------------------\n");
1331 printf("cache: %ikb / %ikb\n",
1332 cache->usage / 1024,
1333 cache->limit / 1024);
1334 printf("................................................................\n");
1335 total = 0;
1336 EINA_INLIST_FOREACH(cache->lru_nodata, im)
1337 _dump_img(im, "NODATA");
1338 EINA_INLIST_FOREACH(cache->lru, im)
1339 _dump_img(im, "DATA ");
1340 printf("tot: %i\n"
1341 "usg: %i\n",
1342 total,
1343 cache->usage);
1344 eina_hash_foreach(cache->activ, _dump_cache_active, NULL);
1345}
1346#endif
1347
1348EAPI int
1349evas_cache_image_flush(Evas_Cache_Image *cache)
1350{
1351#ifdef CACHEDUMP
1352 _dump_cache(cache);
1353#endif
1354 if (cache->limit == (unsigned int)-1) return -1;
1355
1356 while ((cache->lru) && (cache->limit < (unsigned int)cache->usage))
1357 {
1358 Image_Entry *im;
1359
1360 im = (Image_Entry *)cache->lru->last;
1361 _evas_cache_image_entry_delete(cache, im);
1362 }
1363
1364 while ((cache->lru_nodata) && (cache->limit < (unsigned int)cache->usage))
1365 {
1366 Image_Entry *im;
1367
1368 im = (Image_Entry *) cache->lru_nodata->last;
1369 _evas_cache_image_lru_nodata_del(im);
1370 cache->func.surface_delete(im);
1371 im->flags.loaded = 0;
1372 }
1373
1374 return cache->usage;
1375}
1376
1377EAPI Image_Entry *
1378evas_cache_image_empty(Evas_Cache_Image *cache)
1379{
1380 Image_Entry *im;
1381
1382 im = _evas_cache_image_entry_new(cache, NULL, NULL, NULL, NULL, NULL, NULL);
1383 if (!im) return NULL;
1384#ifdef EVAS_FRAME_QUEUING
1385 LKL(im->lock_references);
1386#endif
1387 im->references = 1;
1388#ifdef EVAS_FRAME_QUEUING
1389 LKU(im->lock_references);
1390#endif
1391 return im;
1392}
1393
1394EAPI void
1395evas_cache_image_colorspace(Image_Entry *im, int cspace)
1396{
1397 if (im->space == cspace) return;
1398 im->space = cspace;
1399 im->cache->func.color_space(im, cspace);
1400}
1401
1402EAPI void *
1403evas_cache_private_from_image_entry_get(Image_Entry *im)
1404{
1405 return (void *)im->cache->data;
1406}
1407
1408EAPI void *
1409evas_cache_private_get(Evas_Cache_Image *cache)
1410{
1411 return cache->data;
1412}
1413
1414EAPI void
1415evas_cache_private_set(Evas_Cache_Image *cache, const void *data)
1416{
1417 cache->data = (void *)data;
1418}
1419
1420EAPI DATA32 *
1421evas_cache_image_pixels(Image_Entry *im)
1422{
1423 return im->cache->func.surface_pixels(im);
1424}
1425
1426EAPI void
1427evas_cache_image_wakeup(void)
1428{
1429#ifdef BUILD_ASYNC_PRELOAD
1430 if (_evas_cache_mutex_init > 0)
1431 eina_condition_broadcast(&cond_wakeup);
1432#endif
1433}