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