Blender V4.3
wm_jobs.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include <cstring>
12
14
15#include "MEM_guardedalloc.h"
16
17#include "BLI_blenlib.h"
18#include "BLI_threads.h"
19#include "BLI_time.h"
20#include "BLI_utildefines.h"
21
22#include "BKE_global.hh"
23#include "BKE_report.hh"
24
25#include "SEQ_prefetch.hh"
26
27#include "WM_api.hh"
28#include "WM_types.hh"
29#include "wm.hh"
30#include "wm_event_types.hh"
31
32/*
33 * Add new job
34 * - register in WM
35 * - configure callbacks
36 *
37 * Start or re-run job
38 * - if job running
39 * - signal job to end
40 * - add timer notifier to verify when it has ended, to start it
41 * - else
42 * - start job
43 * - add timer notifier to handle progress
44 *
45 * Stop job
46 * - signal job to end
47 * on end, job will tag itself as sleeping
48 *
49 * Remove job
50 * - signal job to end
51 * on end, job will remove itself
52 *
53 * When job is done:
54 * - it puts timer to sleep (or removes?)
55 */
56
57struct wmJob {
59
62
69 void (*initjob)(void *);
79 void (*update)(void *);
84 void (*free)(void *);
89 void (*endjob)(void *);
94 void (*completed)(void *);
99 void (*canceled)(void *);
100
102 double time_step;
108
109 /* Internal. */
110 const void *owner;
114
117
119 char name[128];
120
123 void (*run_free)(void *);
124
127
129
135};
136
137/* Main thread locking. */
138
143
148
149static void wm_job_main_thread_yield(wmJob *wm_job)
150{
151 /* Unlock and lock the ticket mutex. because it's a fair mutex any job that
152 * is waiting to acquire the lock will get it first, before we can lock. */
155}
156
160static wmJob *wm_job_find(const wmWindowManager *wm, const void *owner, const eWM_JobType job_type)
161{
162 if (owner && (job_type != WM_JOB_TYPE_ANY)) {
163 LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
164 if (wm_job->owner == owner && wm_job->job_type == job_type) {
165 return wm_job;
166 }
167 }
168 }
169 else if (owner) {
170 LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
171 if (wm_job->owner == owner) {
172 return wm_job;
173 }
174 }
175 }
176 else if (job_type != WM_JOB_TYPE_ANY) {
177 LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
178 if (wm_job->job_type == job_type) {
179 return wm_job;
180 }
181 }
182 }
183
184 return nullptr;
185}
186
187/* ******************* public API ***************** */
188
190 wmWindow *win,
191 const void *owner,
192 const char *name,
193 const eWM_JobFlag flag,
194 const eWM_JobType job_type)
195{
196 wmJob *wm_job = wm_job_find(wm, owner, job_type);
197
198 if (wm_job == nullptr) {
199 wm_job = static_cast<wmJob *>(MEM_callocN(sizeof(wmJob), "new job"));
200
201 BLI_addtail(&wm->jobs, wm_job);
202 wm_job->win = win;
203 wm_job->owner = owner;
204 wm_job->flag = flag;
205 wm_job->job_type = job_type;
206 STRNCPY(wm_job->name, name);
207
210
211 wm_job->worker_status.reports = MEM_cnew<ReportList>(__func__);
214 }
215 /* Else: a running job, be careful. */
216
217 /* Prevent creating a job with an invalid type. */
219
220 return wm_job;
221}
222
223bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
224{
225 /* Job can be running or about to run (suspended). */
226 LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
227 if (wm_job->owner != owner) {
228 continue;
229 }
230
231 if (!ELEM(job_type, WM_JOB_TYPE_ANY, wm_job->job_type)) {
232 continue;
233 }
234
235 if ((wm_job->flag & WM_JOB_PROGRESS) && (wm_job->running || wm_job->suspended)) {
236 return true;
237 }
238 }
239
240 return false;
241}
242
243float WM_jobs_progress(const wmWindowManager *wm, const void *owner)
244{
245 const wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY);
246
247 if (wm_job && wm_job->flag & WM_JOB_PROGRESS) {
248 return wm_job->worker_status.progress;
249 }
250
251 return 0.0;
252}
253
255{
256 float total_progress = 0.0f;
257 float jobs_progress = 0;
258
259 LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
260 if (wm_job->threads.first && !wm_job->ready) {
261 if (wm_job->flag & WM_JOB_PROGRESS) {
262 /* Accumulate global progress for running jobs. */
263 jobs_progress++;
264 total_progress += wm_job->worker_status.progress;
265 }
266 }
267 }
268
269 /* If there are running jobs, set the global progress indicator. */
270 if (jobs_progress > 0) {
271 float progress = total_progress / float(jobs_progress);
272
273 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
274 WM_progress_set(win, progress);
275 }
276 }
277 else {
278 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
280 }
281 }
282}
283
284double WM_jobs_starttime(const wmWindowManager *wm, const void *owner)
285{
286 const wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY);
287
288 if (wm_job && wm_job->flag & WM_JOB_PROGRESS) {
289 return wm_job->start_time;
290 }
291
292 return 0;
293}
294
295const char *WM_jobs_name(const wmWindowManager *wm, const void *owner)
296{
297 wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY);
298
299 if (wm_job) {
300 return wm_job->name;
301 }
302
303 return nullptr;
304}
305
306void *WM_jobs_customdata_from_type(wmWindowManager *wm, const void *owner, int job_type)
307{
308 wmJob *wm_job = wm_job_find(wm, owner, eWM_JobType(job_type));
309
310 if (wm_job) {
311 return WM_jobs_customdata_get(wm_job);
312 }
313
314 return nullptr;
315}
316
317bool WM_jobs_is_running(const wmJob *wm_job)
318{
319 return wm_job->running;
320}
321
322bool WM_jobs_is_stopped(const wmWindowManager *wm, const void *owner)
323{
324 wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY);
325 return wm_job ? wm_job->worker_status.stop : true; /* XXX to be redesigned properly. */
326}
327
329{
330 if (!wm_job->customdata) {
331 return wm_job->run_customdata;
332 }
333 return wm_job->customdata;
334}
335
336void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void (*free)(void *customdata))
337{
338 /* Pending job? just free. */
339 if (wm_job->customdata) {
340 wm_job->free(wm_job->customdata);
341 }
342
343 wm_job->customdata = customdata;
344 wm_job->free = free;
345
346 if (wm_job->running) {
347 /* Signal job to end. */
348 wm_job->worker_status.stop = true;
349 }
350}
351
352void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
353{
354 wm_job->time_step = time_step;
355 wm_job->note = note;
356 wm_job->endnote = endnote;
357}
358
359void WM_jobs_delay_start(wmJob *wm_job, double delay_time)
360{
361 wm_job->start_delay_time = delay_time;
362}
363
365 wm_jobs_start_callback startjob,
366 void (*initjob)(void *),
367 void (*update)(void *),
368 void (*endjob)(void *))
369{
370 WM_jobs_callbacks_ex(wm_job, startjob, initjob, update, endjob, nullptr, nullptr);
371}
372
374 wm_jobs_start_callback startjob,
375 void (*initjob)(void *),
376 void (*update)(void *),
377 void (*endjob)(void *),
378 void (*completed)(void *),
379 void (*canceled)(void *))
380{
381 wm_job->startjob = startjob;
382 wm_job->initjob = initjob;
383 wm_job->update = update;
384 wm_job->endjob = endjob;
385 wm_job->completed = completed;
386 wm_job->canceled = canceled;
387}
388
393
394static void *do_job_thread(void *job_v)
395{
396 wmJob *wm_job = static_cast<wmJob *>(job_v);
397
398 wm_job->startjob(wm_job->run_customdata, &wm_job->worker_status);
399 wm_job->ready = true;
400
401 return nullptr;
402}
403
404/* Don't allow same startjob to be executed twice. */
406{
407 bool suspend = false;
408
409 /* Job added with suspend flag, we wait 1 timer step before activating it. */
410 if (test->start_delay_time > 0.0) {
411 suspend = true;
412 test->start_delay_time = 0.0;
413 }
414 else {
415 /* Check other jobs. */
416 LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
417 /* Obvious case, no test needed. */
418 if (wm_job == test || !wm_job->running) {
419 continue;
420 }
421
422 /* If new job is not render, then check for same job type. */
423 if (0 == (test->flag & WM_JOB_EXCL_RENDER)) {
424 if (wm_job->job_type != test->job_type) {
425 continue;
426 }
427 }
428
429 /* If new job is render, any render job should be stopped. */
430 if (test->flag & WM_JOB_EXCL_RENDER) {
431 if (0 == (wm_job->flag & WM_JOB_EXCL_RENDER)) {
432 continue;
433 }
434 }
435
436 suspend = true;
437
438 /* If this job has higher priority, stop others. */
439 if (test->flag & WM_JOB_PRIORITY) {
440 wm_job->worker_status.stop = true;
441 // printf("job stopped: %s\n", wm_job->name);
442 }
443 }
444 }
445
446 /* Possible suspend ourselves, waiting for other jobs, or de-suspend. */
447 test->suspended = suspend;
448#if 0
449 if (suspend) {
450 printf("job suspended: %s\n", test->name);
451 }
452#endif
453}
454
456{
457 if (wm_job->running) {
458 /* Signal job to end and restart. */
459 wm_job->worker_status.stop = true;
460 // printf("job started a running job, ending... %s\n", wm_job->name);
461 }
462 else {
463
464 if (wm_job->customdata && wm_job->startjob) {
465 const double time_step = (wm_job->start_delay_time > 0.0) ? wm_job->start_delay_time :
466 wm_job->time_step;
467
468 wm_jobs_test_suspend_stop(wm, wm_job);
469
470 if (wm_job->suspended == false) {
471 /* Copy to ensure proper free in end. */
472 wm_job->run_customdata = wm_job->customdata;
473 wm_job->run_free = wm_job->free;
474 wm_job->free = nullptr;
475 wm_job->customdata = nullptr;
476 wm_job->running = true;
477
478 if (wm_job->initjob) {
479 wm_job->initjob(wm_job->run_customdata);
480 }
481
482 wm_job->worker_status.stop = false;
483 wm_job->ready = false;
484 wm_job->worker_status.progress = 0.0;
485
486 // printf("job started: %s\n", wm_job->name);
487
489 BLI_threadpool_insert(&wm_job->threads, wm_job);
490 }
491
492 /* Restarted job has timer already. */
493 if (wm_job->wt && (wm_job->wt->time_step > time_step)) {
494 WM_event_timer_remove(wm, wm_job->win, wm_job->wt);
495 wm_job->wt = WM_event_timer_add(wm, wm_job->win, TIMERJOBS, time_step);
496 }
497 if (wm_job->wt == nullptr) {
498 wm_job->wt = WM_event_timer_add(wm, wm_job->win, TIMERJOBS, time_step);
499 }
500
502 }
503 else {
504 printf("job fails, not initialized\n");
505 }
506 }
507}
508
509static void wm_job_end(wmWindowManager *wm, wmJob *wm_job)
510{
511 BLI_assert_msg(BLI_thread_is_main(), "wm_job_end should only be called from the main thread");
512 if (wm_job->endjob) {
513 wm_job->endjob(wm_job->run_customdata);
514 }
515
516 /* Do the final callback based on whether the job was run to completion or not.
517 * Not all jobs have the same way of signaling cancellation (i.e. rendering stops when
518 * `G.is_break == true`, but doesn't set any wm_job properties to cancel the WM job). */
519 const bool was_canceled = wm_job->worker_status.stop || G.is_break;
520 void (*final_callback)(void *) = (wm_job->ready && !was_canceled) ? wm_job->completed :
521 wm_job->canceled;
522 if (final_callback) {
523 final_callback(wm_job->run_customdata);
524 }
525
526 /* Ensure all reports have been moved to WM. */
527 wm_jobs_reports_update(wm, wm_job);
528}
529
530static void wm_job_free(wmWindowManager *wm, wmJob *wm_job)
531{
532 BLI_remlink(&wm->jobs, wm_job);
535
538 MEM_delete(wm_job->worker_status.reports);
539 MEM_freeN(wm_job);
540}
541
542/* Stop job, end thread, free data completely. */
543static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job)
544{
545 bool update_progress = (wm_job->flag & WM_JOB_PROGRESS) != 0;
546
547 if (wm_job->running) {
548 /* Signal job to end. */
549 wm_job->worker_status.stop = true;
550
552 BLI_threadpool_end(&wm_job->threads);
554 wm_job_end(wm, wm_job);
555 }
556
557 if (wm_job->wt) {
558 WM_event_timer_remove(wm, wm_job->win, wm_job->wt);
559 }
560 if (wm_job->customdata) {
561 wm_job->free(wm_job->customdata);
562 }
563 if (wm_job->run_customdata) {
564 wm_job->run_free(wm_job->run_customdata);
565 }
566
567 /* Remove wm_job. */
568 wm_job_free(wm, wm_job);
569
570 /* Update progress bars in windows. */
571 if (update_progress) {
573 }
574}
575
577{
578 wmJob *wm_job;
579
580 while ((wm_job = static_cast<wmJob *>(wm->jobs.first))) {
581 wm_jobs_kill_job(wm, wm_job);
582 }
583
584 /* This job will be automatically restarted. */
586}
587
588void WM_jobs_kill_all_except(wmWindowManager *wm, const void *owner)
589{
590 LISTBASE_FOREACH_MUTABLE (wmJob *, wm_job, &wm->jobs) {
591 if (wm_job->owner != owner) {
592 wm_jobs_kill_job(wm, wm_job);
593 }
594 }
595}
596
597void WM_jobs_kill_type(wmWindowManager *wm, const void *owner, int job_type)
598{
599 BLI_assert(job_type != WM_JOB_TYPE_ANY);
600
601 LISTBASE_FOREACH_MUTABLE (wmJob *, wm_job, &wm->jobs) {
602 if (owner && wm_job->owner != owner) {
603 continue;
604 }
605
606 if (wm_job->job_type == job_type) {
607 wm_jobs_kill_job(wm, wm_job);
608 }
609 }
610}
611
613{
614 LISTBASE_FOREACH_MUTABLE (wmJob *, wm_job, &wm->jobs) {
615 if (wm_job->owner == owner) {
616 wm_jobs_kill_job(wm, wm_job);
617 }
618 }
619}
620
621void WM_jobs_stop_type(wmWindowManager *wm, const void *owner, eWM_JobType job_type)
622{
623 BLI_assert(job_type != WM_JOB_TYPE_ANY);
624
625 LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
626 if (owner && wm_job->owner != owner) {
627 continue;
628 }
629 if (wm_job->job_type == job_type) {
630 if (wm_job->running) {
631 wm_job->worker_status.stop = true;
632 }
633 }
634 }
635}
636
638{
639 LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
640 if (wm_job->owner == owner) {
641 if (wm_job->running) {
642 wm_job->worker_status.stop = true;
643 }
644 }
645 }
646}
647
649{
650 wmJob *wm_job = static_cast<wmJob *>(BLI_findptr(&wm->jobs, wt, offsetof(wmJob, wt)));
651 if (wm_job) {
652 wm_jobs_kill_job(wm, wm_job);
653 }
654}
655
657{
658 wmJob *wm_job = static_cast<wmJob *>(BLI_findptr(&wm->jobs, wt, offsetof(wmJob, wt)));
659
660 if (wm_job) {
661 /* Running threads. */
662 if (wm_job->threads.first) {
663 /* Let threads get temporary lock over main thread if needed. */
665
666 /* Always call note and update when ready. */
667 if (wm_job->worker_status.do_update || wm_job->ready) {
668 if (wm_job->update) {
669 wm_job->update(wm_job->run_customdata);
670 }
671 if (wm_job->note) {
672 WM_event_add_notifier_ex(wm, wm_job->win, wm_job->note, nullptr);
673 }
674
675 if (wm_job->flag & WM_JOB_PROGRESS) {
676 WM_event_add_notifier_ex(wm, wm_job->win, NC_WM | ND_JOB, nullptr);
677 }
678 wm_job->worker_status.do_update = false;
679 }
680
681 if (wm_job->ready) {
682 wm_job_end(wm, wm_job);
683
684 /* Free owned data. */
685 wm_job->run_free(wm_job->run_customdata);
686 wm_job->run_customdata = nullptr;
687 wm_job->run_free = nullptr;
688
689#if 0
690 if (wm_job->stop) {
691 printf("job ready but stopped %s\n", wm_job->name);
692 }
693 else {
694 printf("job finished %s\n", wm_job->name);
695 }
696#endif
697
698 if (G.debug & G_DEBUG_JOBS) {
699 printf("Job '%s' finished in %f seconds\n",
700 wm_job->name,
701 BLI_time_now_seconds() - wm_job->start_time);
702 }
703
704 wm_job->running = false;
705
707 BLI_threadpool_end(&wm_job->threads);
709
710 if (wm_job->endnote) {
711 WM_event_add_notifier_ex(wm, wm_job->win, wm_job->endnote, nullptr);
712 }
713
714 WM_event_add_notifier_ex(wm, wm_job->win, NC_WM | ND_JOB, nullptr);
715
716 /* New job added for wm_job? */
717 if (wm_job->customdata) {
718 // printf("job restarted with new data %s\n", wm_job->name);
719 WM_jobs_start(wm, wm_job);
720 }
721 else {
722 WM_event_timer_remove(wm, wm_job->win, wm_job->wt);
723 wm_job->wt = nullptr;
724
725 /* Remove wm_job. */
726 wm_job_free(wm, wm_job);
727 wm_job = nullptr;
728 }
729 }
730 }
731 else if (wm_job->suspended) {
732 WM_jobs_start(wm, wm_job);
733 }
734
735 /* Move pending reports generated by the worker thread to the WM main list. */
736 if (wm_job) {
737 wm_jobs_reports_update(wm, wm_job);
738 }
739 }
740
741 /* Update progress bars in windows. */
743}
744
746{
747 LISTBASE_FOREACH (const wmJob *, wm_job, &wm->jobs) {
748 if (wm_job->running) {
749 return true;
750 }
751 }
752
753 return false;
754}
755
756bool WM_jobs_has_running_type(const wmWindowManager *wm, int job_type)
757{
758 LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
759 if (wm_job->running && wm_job->job_type == job_type) {
760 return true;
761 }
762 }
763 return false;
764}
@ G_DEBUG_JOBS
void BKE_reports_free(ReportList *reports)
Definition report.cc:69
void BKE_report_print_level_set(ReportList *reports, eReportType level)
Definition report.cc:237
void BKE_reports_init(ReportList *reports, int flag)
Definition report.cc:54
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
void BLI_kdtree_nd_ free(KDTree *tree)
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
void * BLI_findptr(const struct ListBase *listbase, const void *ptr, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
unsigned int uint
TicketMutex * BLI_ticket_mutex_alloc(void)
Definition threads.cc:511
void BLI_ticket_mutex_unlock(TicketMutex *ticket)
Definition threads.cc:564
void BLI_threadpool_init(struct ListBase *threadbase, void *(*do_thread)(void *), int tot)
Definition threads.cc:121
void BLI_threadpool_end(struct ListBase *threadbase)
Definition threads.cc:234
void BLI_ticket_mutex_lock(TicketMutex *ticket)
Definition threads.cc:554
void BLI_ticket_mutex_free(TicketMutex *ticket)
Definition threads.cc:522
int BLI_thread_is_main(void)
Definition threads.cc:179
void BLI_threadpool_insert(struct ListBase *threadbase, void *callerdata)
Definition threads.cc:184
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.c:65
#define ELEM(...)
Read Guarded memory(de)allocation.
eWM_JobType
Definition WM_api.hh:1573
@ WM_JOB_TYPE_ANY
Definition WM_api.hh:1575
void(*)(void *custom_data, wmJobWorkerStatus *worker_status) wm_jobs_start_callback
Definition WM_api.hh:1648
eWM_JobFlag
Definition WM_api.hh:1559
@ WM_JOB_EXCL_RENDER
Definition WM_api.hh:1565
@ WM_JOB_PROGRESS
Definition WM_api.hh:1566
@ WM_JOB_PRIORITY
Definition WM_api.hh:1560
#define ND_JOB
Definition WM_types.hh:383
#define NC_WM
Definition WM_types.hh:341
#define printf
#define offsetof(t, d)
draw_view in_light_buf[] float
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
#define G(x, y, z)
static void update(bNodeTree *ntree)
void SEQ_prefetch_stop_all()
Definition prefetch.cc:237
void * first
ReportList * reports
Definition WM_types.hh:985
double time_step
Definition wm_jobs.cc:102
wm_jobs_start_callback startjob
Definition wm_jobs.cc:74
bool ready
Definition wm_jobs.cc:112
void(* update)(void *)
Definition wm_jobs.cc:79
void(* initjob)(void *)
Definition wm_jobs.cc:69
void(* completed)(void *)
Definition wm_jobs.cc:94
bool running
Definition wm_jobs.cc:112
void(* run_free)(void *)
Definition wm_jobs.cc:123
void * run_customdata
Definition wm_jobs.cc:122
uint endnote
Definition wm_jobs.cc:107
eWM_JobFlag flag
Definition wm_jobs.cc:111
wmJob * next
Definition wm_jobs.cc:58
void(* canceled)(void *)
Definition wm_jobs.cc:99
TicketMutex * main_thread_mutex
Definition wm_jobs.cc:134
void * customdata
Definition wm_jobs.cc:64
void(* free)(void *)
Definition wm_jobs.cc:84
bool suspended
Definition wm_jobs.cc:112
const void * owner
Definition wm_jobs.cc:110
ListBase threads
Definition wm_jobs.cc:126
eWM_JobType job_type
Definition wm_jobs.cc:113
char name[128]
Definition wm_jobs.cc:119
uint note
Definition wm_jobs.cc:107
wmJobWorkerStatus worker_status
Definition wm_jobs.cc:116
double start_time
Definition wm_jobs.cc:128
wmJob * prev
Definition wm_jobs.cc:58
double start_delay_time
Definition wm_jobs.cc:105
wmTimer * wt
Definition wm_jobs.cc:103
void(* endjob)(void *)
Definition wm_jobs.cc:89
wmWindow * win
Definition wm_jobs.cc:61
double time_step
Definition WM_types.hh:916
void WM_event_add_notifier_ex(wmWindowManager *wm, const wmWindow *win, uint type, void *reference)
void WM_reports_from_reports_move(wmWindowManager *wm, ReportList *reports)
@ TIMERJOBS
static void wm_jobs_reports_update(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:389
bool WM_jobs_has_running_type(const wmWindowManager *wm, int job_type)
Definition wm_jobs.cc:756
static void wm_job_free(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:530
void WM_jobs_kill_all_from_owner(wmWindowManager *wm, const void *owner)
Definition wm_jobs.cc:612
bool WM_jobs_is_running(const wmJob *wm_job)
Definition wm_jobs.cc:317
static void wm_job_main_thread_yield(wmJob *wm_job)
Definition wm_jobs.cc:149
void WM_jobs_stop_type(wmWindowManager *wm, const void *owner, eWM_JobType job_type)
Definition wm_jobs.cc:621
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
Definition wm_jobs.cc:352
void WM_jobs_stop_all_from_owner(wmWindowManager *wm, const void *owner)
Definition wm_jobs.cc:637
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:455
const char * WM_jobs_name(const wmWindowManager *wm, const void *owner)
Definition wm_jobs.cc:295
static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:543
void wm_jobs_timer_end(wmWindowManager *wm, wmTimer *wt)
Definition wm_jobs.cc:648
void WM_jobs_kill_type(wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:597
bool WM_jobs_has_running(const wmWindowManager *wm)
Definition wm_jobs.cc:745
bool WM_jobs_is_stopped(const wmWindowManager *wm, const void *owner)
Definition wm_jobs.cc:322
static void wm_jobs_test_suspend_stop(wmWindowManager *wm, wmJob *test)
Definition wm_jobs.cc:405
void * WM_jobs_customdata_get(wmJob *wm_job)
Definition wm_jobs.cc:328
void WM_jobs_kill_all(wmWindowManager *wm)
Definition wm_jobs.cc:576
void WM_jobs_delay_start(wmJob *wm_job, double delay_time)
Definition wm_jobs.cc:359
float WM_jobs_progress(const wmWindowManager *wm, const void *owner)
Definition wm_jobs.cc:243
static void wm_job_end(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:509
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, const eWM_JobFlag flag, const eWM_JobType job_type)
Definition wm_jobs.cc:189
static void wm_jobs_update_progress_bars(wmWindowManager *wm)
Definition wm_jobs.cc:254
double WM_jobs_starttime(const wmWindowManager *wm, const void *owner)
Definition wm_jobs.cc:284
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
Definition wm_jobs.cc:364
void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt)
Definition wm_jobs.cc:656
void WM_jobs_callbacks_ex(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *), void(*completed)(void *), void(*canceled)(void *))
Definition wm_jobs.cc:373
void WM_jobs_kill_all_except(wmWindowManager *wm, const void *owner)
Definition wm_jobs.cc:588
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:223
void WM_job_main_thread_lock_acquire(wmJob *wm_job)
Definition wm_jobs.cc:139
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:336
void WM_job_main_thread_lock_release(wmJob *wm_job)
Definition wm_jobs.cc:144
static wmJob * wm_job_find(const wmWindowManager *wm, const void *owner, const eWM_JobType job_type)
Definition wm_jobs.cc:160
static void * do_job_thread(void *job_v)
Definition wm_jobs.cc:394
void * WM_jobs_customdata_from_type(wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:306
void WM_progress_clear(wmWindow *win)
void WM_progress_set(wmWindow *win, float progress)
void WM_event_timer_remove(wmWindowManager *wm, wmWindow *, wmTimer *timer)
wmTimer * WM_event_timer_add(wmWindowManager *wm, wmWindow *win, const int event_type, const double time_step)
uint8_t flag
Definition wm_window.cc:138