Blender  V3.3
wm_jobs.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2009 Blender Foundation. All rights reserved. */
3 
10 #include <string.h>
11 
13 
14 #include "MEM_guardedalloc.h"
15 
16 #include "BLI_blenlib.h"
17 #include "BLI_threads.h"
18 #include "BLI_utildefines.h"
19 
20 #include "BKE_context.h"
21 #include "BKE_global.h"
22 
23 #include "SEQ_prefetch.h"
24 
25 #include "WM_api.h"
26 #include "WM_types.h"
27 #include "wm.h"
28 #include "wm_event_types.h"
29 
30 #include "PIL_time.h"
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 
57 struct wmJob {
58  struct wmJob *next, *prev;
59 
62 
64  void *customdata;
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 timestep;
107  unsigned int note, endnote;
108 
109  /* internal */
110  const void *owner;
111  int flag;
113  float progress;
114 
116  char name[128];
117 
120  void (*run_free)(void *);
121 
124 
125  double start_time;
126 
130 };
131 
132 /* Main thread locking */
133 
135 {
137 }
138 
140 {
142 }
143 
144 static void wm_job_main_thread_yield(wmJob *wm_job)
145 {
146  /* unlock and lock the ticket mutex. because it's a fair mutex any job that
147  * is waiting to acquire the lock will get it first, before we can lock */
150 }
151 
155 static wmJob *wm_job_find(const wmWindowManager *wm, const void *owner, const int job_type)
156 {
157  if (owner && job_type) {
158  LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
159  if (wm_job->owner == owner && wm_job->job_type == job_type) {
160  return wm_job;
161  }
162  }
163  }
164  else if (owner) {
165  LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
166  if (wm_job->owner == owner) {
167  return wm_job;
168  }
169  }
170  }
171  else if (job_type) {
172  LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
173  if (wm_job->job_type == job_type) {
174  return wm_job;
175  }
176  }
177  }
178 
179  return NULL;
180 }
181 
182 /* ******************* public API ***************** */
183 
185  wmWindow *win,
186  const void *owner,
187  const char *name,
188  int flag,
189  int job_type)
190 {
191  wmJob *wm_job = wm_job_find(wm, owner, job_type);
192 
193  if (wm_job == NULL) {
194  wm_job = MEM_callocN(sizeof(wmJob), "new job");
195 
196  BLI_addtail(&wm->jobs, wm_job);
197  wm_job->win = win;
198  wm_job->owner = owner;
199  wm_job->flag = flag;
200  wm_job->job_type = job_type;
201  BLI_strncpy(wm_job->name, name, sizeof(wm_job->name));
202 
205  }
206  /* else: a running job, be careful */
207 
208  /* prevent creating a job with an invalid type */
209  BLI_assert(wm_job->job_type != WM_JOB_TYPE_ANY);
210 
211  return wm_job;
212 }
213 
214 bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
215 {
216  /* job can be running or about to run (suspended) */
217  LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
218  if (wm_job->owner == owner) {
219  if (ELEM(job_type, WM_JOB_TYPE_ANY, wm_job->job_type)) {
220  if ((wm_job->flag & WM_JOB_PROGRESS) && (wm_job->running || wm_job->suspended)) {
221  return true;
222  }
223  }
224  }
225  }
226 
227  return false;
228 }
229 
230 float WM_jobs_progress(const wmWindowManager *wm, const void *owner)
231 {
232  const wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY);
233 
234  if (wm_job && wm_job->flag & WM_JOB_PROGRESS) {
235  return wm_job->progress;
236  }
237 
238  return 0.0;
239 }
240 
242 {
243  float total_progress = 0.0f;
244  float jobs_progress = 0;
245 
246  LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
247  if (wm_job->threads.first && !wm_job->ready) {
248  if (wm_job->flag & WM_JOB_PROGRESS) {
249  /* accumulate global progress for running jobs */
250  jobs_progress++;
251  total_progress += wm_job->progress;
252  }
253  }
254  }
255 
256  /* if there are running jobs, set the global progress indicator */
257  if (jobs_progress > 0) {
258  float progress = total_progress / (float)jobs_progress;
259 
260  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
262  }
263  }
264  else {
265  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
267  }
268  }
269 }
270 
271 double WM_jobs_starttime(const wmWindowManager *wm, const void *owner)
272 {
273  const wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY);
274 
275  if (wm_job && wm_job->flag & WM_JOB_PROGRESS) {
276  return wm_job->start_time;
277  }
278 
279  return 0;
280 }
281 
282 const char *WM_jobs_name(const wmWindowManager *wm, const void *owner)
283 {
284  wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY);
285 
286  if (wm_job) {
287  return wm_job->name;
288  }
289 
290  return NULL;
291 }
292 
294 {
295  wmJob *wm_job = wm_job_find(wm, owner, job_type);
296 
297  if (wm_job) {
298  return WM_jobs_customdata_get(wm_job);
299  }
300 
301  return NULL;
302 }
303 
304 bool WM_jobs_is_running(const wmJob *wm_job)
305 {
306  return wm_job->running;
307 }
308 
309 bool WM_jobs_is_stopped(const wmWindowManager *wm, const void *owner)
310 {
311  wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY);
312  return wm_job ? wm_job->stop : true; /* XXX to be redesigned properly. */
313 }
314 
316 {
317  if (!wm_job->customdata) {
318  return wm_job->run_customdata;
319  }
320  return wm_job->customdata;
321 }
322 
323 void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void (*free)(void *))
324 {
325  /* pending job? just free */
326  if (wm_job->customdata) {
327  wm_job->free(wm_job->customdata);
328  }
329 
330  wm_job->customdata = customdata;
331  wm_job->free = free;
332 
333  if (wm_job->running) {
334  /* signal job to end */
335  wm_job->stop = true;
336  }
337 }
338 
339 void WM_jobs_timer(wmJob *wm_job, double timestep, unsigned int note, unsigned int endnote)
340 {
341  wm_job->timestep = timestep;
342  wm_job->note = note;
343  wm_job->endnote = endnote;
344 }
345 
346 void WM_jobs_delay_start(wmJob *wm_job, double delay_time)
347 {
348  wm_job->start_delay_time = delay_time;
349 }
350 
353  void (*initjob)(void *),
354  void (*update)(void *),
355  void (*endjob)(void *))
356 {
358 }
359 
362  void (*initjob)(void *),
363  void (*update)(void *),
364  void (*endjob)(void *),
365  void (*completed)(void *),
366  void (*canceled)(void *))
367 {
368  wm_job->startjob = startjob;
369  wm_job->initjob = initjob;
370  wm_job->update = update;
371  wm_job->endjob = endjob;
372  wm_job->completed = completed;
373  wm_job->canceled = canceled;
374 }
375 
376 static void *do_job_thread(void *job_v)
377 {
378  wmJob *wm_job = job_v;
379 
380  wm_job->startjob(wm_job->run_customdata, &wm_job->stop, &wm_job->do_update, &wm_job->progress);
381  wm_job->ready = true;
382 
383  return NULL;
384 }
385 
386 /* don't allow same startjob to be executed twice */
388 {
389  bool suspend = false;
390 
391  /* job added with suspend flag, we wait 1 timer step before activating it */
392  if (test->start_delay_time > 0.0) {
393  suspend = true;
394  test->start_delay_time = 0.0;
395  }
396  else {
397  /* check other jobs */
398  LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
399  /* obvious case, no test needed */
400  if (wm_job == test || !wm_job->running) {
401  continue;
402  }
403 
404  /* if new job is not render, then check for same startjob */
405  if (0 == (test->flag & WM_JOB_EXCL_RENDER)) {
406  if (wm_job->startjob != test->startjob) {
407  continue;
408  }
409  }
410 
411  /* if new job is render, any render job should be stopped */
412  if (test->flag & WM_JOB_EXCL_RENDER) {
413  if (0 == (wm_job->flag & WM_JOB_EXCL_RENDER)) {
414  continue;
415  }
416  }
417 
418  suspend = true;
419 
420  /* if this job has higher priority, stop others */
421  if (test->flag & WM_JOB_PRIORITY) {
422  wm_job->stop = true;
423  // printf("job stopped: %s\n", wm_job->name);
424  }
425  }
426  }
427 
428  /* Possible suspend ourselves, waiting for other jobs, or de-suspend. */
429  test->suspended = suspend;
430 #if 0
431  if (suspend) {
432  printf("job suspended: %s\n", test->name);
433  }
434 #endif
435 }
436 
438 {
439  if (wm_job->running) {
440  /* signal job to end and restart */
441  wm_job->stop = true;
442  // printf("job started a running job, ending... %s\n", wm_job->name);
443  }
444  else {
445 
446  if (wm_job->customdata && wm_job->startjob) {
447  const double timestep = (wm_job->start_delay_time > 0.0) ? wm_job->start_delay_time :
448  wm_job->timestep;
449 
450  wm_jobs_test_suspend_stop(wm, wm_job);
451 
452  if (wm_job->suspended == false) {
453  /* copy to ensure proper free in end */
454  wm_job->run_customdata = wm_job->customdata;
455  wm_job->run_free = wm_job->free;
456  wm_job->free = NULL;
457  wm_job->customdata = NULL;
458  wm_job->running = true;
459 
460  if (wm_job->initjob) {
461  wm_job->initjob(wm_job->run_customdata);
462  }
463 
464  wm_job->stop = false;
465  wm_job->ready = false;
466  wm_job->progress = 0.0;
467 
468  // printf("job started: %s\n", wm_job->name);
469 
471  BLI_threadpool_insert(&wm_job->threads, wm_job);
472  }
473 
474  /* restarted job has timer already */
475  if (wm_job->wt && (wm_job->wt->timestep > timestep)) {
476  WM_event_remove_timer(wm, wm_job->win, wm_job->wt);
477  wm_job->wt = WM_event_add_timer(wm, wm_job->win, TIMERJOBS, timestep);
478  }
479  if (wm_job->wt == NULL) {
480  wm_job->wt = WM_event_add_timer(wm, wm_job->win, TIMERJOBS, timestep);
481  }
482 
484  }
485  else {
486  printf("job fails, not initialized\n");
487  }
488  }
489 }
490 
491 static void wm_job_end(wmJob *wm_job)
492 {
493  BLI_assert_msg(BLI_thread_is_main(), "wm_job_end should only be called from the main thread");
494  if (wm_job->endjob) {
495  wm_job->endjob(wm_job->run_customdata);
496  }
497 
498  /* Do the final callback based on whether the job was run to completion or not.
499  * Not all jobs have the same way of signaling cancellation (i.e. rendering stops when
500  * `G.is_break == true`, but doesn't set any wm_job properties to cancel the WM job). */
501  const bool was_canceled = wm_job->stop || G.is_break;
502  void (*final_callback)(void *) = (wm_job->ready && !was_canceled) ? wm_job->completed :
503  wm_job->canceled;
504  if (final_callback) {
505  final_callback(wm_job->run_customdata);
506  }
507 }
508 
509 static void wm_job_free(wmWindowManager *wm, wmJob *wm_job)
510 {
511  BLI_remlink(&wm->jobs, wm_job);
514  MEM_freeN(wm_job);
515 }
516 
517 /* stop job, end thread, free data completely */
518 static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job)
519 {
520  bool update_progress = (wm_job->flag & WM_JOB_PROGRESS) != 0;
521 
522  if (wm_job->running) {
523  /* signal job to end */
524  wm_job->stop = true;
525 
527  BLI_threadpool_end(&wm_job->threads);
529  wm_job_end(wm_job);
530  }
531 
532  if (wm_job->wt) {
533  WM_event_remove_timer(wm, wm_job->win, wm_job->wt);
534  }
535  if (wm_job->customdata) {
536  wm_job->free(wm_job->customdata);
537  }
538  if (wm_job->run_customdata) {
539  wm_job->run_free(wm_job->run_customdata);
540  }
541 
542  /* remove wm_job */
543  wm_job_free(wm, wm_job);
544 
545  /* Update progress bars in windows. */
546  if (update_progress) {
548  }
549 }
550 
552 {
553  wmJob *wm_job;
554 
555  while ((wm_job = wm->jobs.first)) {
556  wm_jobs_kill_job(wm, wm_job);
557  }
558 
559  /* This job will be automatically restarted */
561 }
562 
564 {
565  LISTBASE_FOREACH_MUTABLE (wmJob *, wm_job, &wm->jobs) {
566  if (wm_job->owner != owner) {
567  wm_jobs_kill_job(wm, wm_job);
568  }
569  }
570 }
571 
572 void WM_jobs_kill_type(struct wmWindowManager *wm, const void *owner, int job_type)
573 {
574  LISTBASE_FOREACH_MUTABLE (wmJob *, wm_job, &wm->jobs) {
575  if (!owner || wm_job->owner == owner) {
576  if (ELEM(job_type, WM_JOB_TYPE_ANY, wm_job->job_type)) {
577  wm_jobs_kill_job(wm, wm_job);
578  }
579  }
580  }
581 }
582 
583 void WM_jobs_stop(wmWindowManager *wm, const void *owner, void *startjob)
584 {
585  LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
586  if (wm_job->owner == owner || wm_job->startjob == startjob) {
587  if (wm_job->running) {
588  wm_job->stop = true;
589  }
590  }
591  }
592 }
593 
595  void *owner,
596  void (*startjob)(void *, short int *, short int *, float *))
597 {
598  LISTBASE_FOREACH_MUTABLE (wmJob *, wm_job, &wm->jobs) {
599  if (wm_job->owner == owner || wm_job->startjob == startjob) {
600  wm_jobs_kill_job(wm, wm_job);
601  }
602  }
603 }
604 
606 {
607  LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
608  if (wm_job->wt == wt) {
609  wm_jobs_kill_job(wm, wm_job);
610  return;
611  }
612  }
613 }
614 
616 {
617  LISTBASE_FOREACH_MUTABLE (wmJob *, wm_job, &wm->jobs) {
618  if (wm_job->wt == wt) {
619  /* running threads */
620  if (wm_job->threads.first) {
621 
622  /* let threads get temporary lock over main thread if needed */
623  wm_job_main_thread_yield(wm_job);
624 
625  /* always call note and update when ready */
626  if (wm_job->do_update || wm_job->ready) {
627  if (wm_job->update) {
628  wm_job->update(wm_job->run_customdata);
629  }
630  if (wm_job->note) {
631  WM_event_add_notifier_ex(wm, wm_job->win, wm_job->note, NULL);
632  }
633 
634  if (wm_job->flag & WM_JOB_PROGRESS) {
635  WM_event_add_notifier_ex(wm, wm_job->win, NC_WM | ND_JOB, NULL);
636  }
637  wm_job->do_update = false;
638  }
639 
640  if (wm_job->ready) {
641  wm_job_end(wm_job);
642 
643  /* free own data */
644  wm_job->run_free(wm_job->run_customdata);
645  wm_job->run_customdata = NULL;
646  wm_job->run_free = NULL;
647 
648 #if 0
649  if (wm_job->stop) {
650  printf("job ready but stopped %s\n", wm_job->name);
651  }
652  else {
653  printf("job finished %s\n", wm_job->name);
654  }
655 #endif
656 
657  if (G.debug & G_DEBUG_JOBS) {
658  printf("Job '%s' finished in %f seconds\n",
659  wm_job->name,
660  PIL_check_seconds_timer() - wm_job->start_time);
661  }
662 
663  wm_job->running = false;
664 
666  BLI_threadpool_end(&wm_job->threads);
668 
669  if (wm_job->endnote) {
670  WM_event_add_notifier_ex(wm, wm_job->win, wm_job->endnote, NULL);
671  }
672 
673  WM_event_add_notifier_ex(wm, wm_job->win, NC_WM | ND_JOB, NULL);
674 
675  /* new job added for wm_job? */
676  if (wm_job->customdata) {
677  // printf("job restarted with new data %s\n", wm_job->name);
678  WM_jobs_start(wm, wm_job);
679  }
680  else {
681  WM_event_remove_timer(wm, wm_job->win, wm_job->wt);
682  wm_job->wt = NULL;
683 
684  /* remove wm_job */
685  wm_job_free(wm, wm_job);
686  }
687  }
688  }
689  else if (wm_job->suspended) {
690  WM_jobs_start(wm, wm_job);
691  }
692  }
693  }
694 
695  /* Update progress bars in windows. */
697 }
698 
700 {
701  LISTBASE_FOREACH (const wmJob *, wm_job, &wm->jobs) {
702  if (wm_job->running) {
703  return true;
704  }
705  }
706 
707  return false;
708 }
709 
711 {
712  LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
713  if (wm_job->running && wm_job->job_type == job_type) {
714  return true;
715  }
716  }
717  return false;
718 }
typedef float(TangentPoint)[2]
@ G_DEBUG_JOBS
Definition: BKE_global.h:180
#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)
Definition: kdtree_impl.h:102
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:354
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
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:134
void BLI_threadpool_end(struct ListBase *threadbase)
Definition: threads.cc:262
void BLI_ticket_mutex_lock(TicketMutex *ticket)
Definition: threads.cc:548
void BLI_ticket_mutex_free(TicketMutex *ticket)
Definition: threads.cc:541
int BLI_thread_is_main(void)
Definition: threads.cc:207
void BLI_threadpool_insert(struct ListBase *threadbase, void *callerdata)
Definition: threads.cc:212
TicketMutex * BLI_ticket_mutex_alloc(void)
Definition: threads.cc:530
#define ELEM(...)
Read Guarded memory(de)allocation.
Platform independent time functions.
void(* wm_jobs_start_callback)(void *custom_data, short *stop, short *do_update, float *progress)
Definition: WM_api.h:1412
@ WM_JOB_EXCL_RENDER
Definition: WM_api.h:1338
@ WM_JOB_PROGRESS
Definition: WM_api.h:1339
@ WM_JOB_PRIORITY
Definition: WM_api.h:1337
@ WM_JOB_TYPE_ANY
Definition: WM_api.h:1347
#define ND_JOB
Definition: WM_types.h:364
#define NC_WM
Definition: WM_types.h:324
SyclQueue void void size_t num_bytes void
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
#define G(x, y, z)
static void update(bNodeTree *ntree)
void SEQ_prefetch_stop_all(void)
Definition: prefetch.c:246
void * first
Definition: DNA_listBase.h:31
Definition: wm_jobs.c:57
double timestep
Definition: wm_jobs.c:102
int flag
Definition: wm_jobs.c:111
short job_type
Definition: wm_jobs.c:112
wm_jobs_start_callback startjob
Definition: wm_jobs.c:74
void(* update)(void *)
Definition: wm_jobs.c:79
short running
Definition: wm_jobs.c:112
void(* initjob)(void *)
Definition: wm_jobs.c:69
struct wmJob * prev
Definition: wm_jobs.c:58
short ready
Definition: wm_jobs.c:112
void(* completed)(void *)
Definition: wm_jobs.c:94
void(* run_free)(void *)
Definition: wm_jobs.c:120
void * run_customdata
Definition: wm_jobs.c:119
short do_update
Definition: wm_jobs.c:112
unsigned int note
Definition: wm_jobs.c:107
void(* canceled)(void *)
Definition: wm_jobs.c:99
TicketMutex * main_thread_mutex
Definition: wm_jobs.c:129
void * customdata
Definition: wm_jobs.c:64
void(* free)(void *)
Definition: wm_jobs.c:84
const void * owner
Definition: wm_jobs.c:110
ListBase threads
Definition: wm_jobs.c:123
char name[128]
Definition: wm_jobs.c:116
short suspended
Definition: wm_jobs.c:112
unsigned int endnote
Definition: wm_jobs.c:107
short stop
Definition: wm_jobs.c:112
double start_time
Definition: wm_jobs.c:125
double start_delay_time
Definition: wm_jobs.c:105
wmTimer * wt
Definition: wm_jobs.c:103
void(* endjob)(void *)
Definition: wm_jobs.c:89
float progress
Definition: wm_jobs.c:113
struct wmJob * next
Definition: wm_jobs.c:58
wmWindow * win
Definition: wm_jobs.c:61
double timestep
Definition: WM_types.h:863
double PIL_check_seconds_timer(void)
Definition: time.c:64
void WM_event_add_notifier_ex(wmWindowManager *wm, const wmWindow *win, uint type, void *reference)
@ TIMERJOBS
static void wm_job_end(wmJob *wm_job)
Definition: wm_jobs.c:491
bool WM_jobs_has_running_type(const struct wmWindowManager *wm, int job_type)
Definition: wm_jobs.c:710
static void wm_job_free(wmWindowManager *wm, wmJob *wm_job)
Definition: wm_jobs.c:509
bool WM_jobs_is_running(const wmJob *wm_job)
Definition: wm_jobs.c:304
static void wm_job_main_thread_yield(wmJob *wm_job)
Definition: wm_jobs.c:144
void WM_jobs_kill(wmWindowManager *wm, void *owner, void(*startjob)(void *, short int *, short int *, float *))
Definition: wm_jobs.c:594
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition: wm_jobs.c:437
static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job)
Definition: wm_jobs.c:518
const char * WM_jobs_name(const wmWindowManager *wm, const void *owner)
Definition: wm_jobs.c:282
void wm_jobs_timer_end(wmWindowManager *wm, wmTimer *wt)
Definition: wm_jobs.c:605
void * WM_jobs_customdata_from_type(wmWindowManager *wm, const void *owner, int job_type)
Definition: wm_jobs.c:293
void WM_jobs_kill_type(struct wmWindowManager *wm, const void *owner, int job_type)
Definition: wm_jobs.c:572
bool WM_jobs_has_running(const wmWindowManager *wm)
Definition: wm_jobs.c:699
bool WM_jobs_is_stopped(const wmWindowManager *wm, const void *owner)
Definition: wm_jobs.c:309
static void wm_jobs_test_suspend_stop(wmWindowManager *wm, wmJob *test)
Definition: wm_jobs.c:387
void WM_jobs_kill_all(wmWindowManager *wm)
Definition: wm_jobs.c:551
void WM_jobs_delay_start(wmJob *wm_job, double delay_time)
Definition: wm_jobs.c:346
float WM_jobs_progress(const wmWindowManager *wm, const void *owner)
Definition: wm_jobs.c:230
static void wm_jobs_update_progress_bars(wmWindowManager *wm)
Definition: wm_jobs.c:241
double WM_jobs_starttime(const wmWindowManager *wm, const void *owner)
Definition: wm_jobs.c:271
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
Definition: wm_jobs.c:351
void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt)
Definition: wm_jobs.c:615
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.c:360
void * WM_jobs_customdata_get(wmJob *wm_job)
Definition: wm_jobs.c:315
void WM_jobs_kill_all_except(wmWindowManager *wm, const void *owner)
Definition: wm_jobs.c:563
static wmJob * wm_job_find(const wmWindowManager *wm, const void *owner, const int job_type)
Definition: wm_jobs.c:155
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition: wm_jobs.c:214
void WM_job_main_thread_lock_acquire(wmJob *wm_job)
Definition: wm_jobs.c:134
void WM_jobs_stop(wmWindowManager *wm, const void *owner, void *startjob)
Definition: wm_jobs.c:583
static void * do_job_thread(void *job_v)
Definition: wm_jobs.c:376
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *))
Definition: wm_jobs.c:323
void WM_jobs_timer(wmJob *wm_job, double timestep, unsigned int note, unsigned int endnote)
Definition: wm_jobs.c:339
void WM_job_main_thread_lock_release(wmJob *wm_job)
Definition: wm_jobs.c:139
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, int flag, int job_type)
Definition: wm_jobs.c:184
void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer)
Definition: wm_window.c:1682
void WM_progress_clear(wmWindow *win)
Definition: wm_window.c:1833
void WM_progress_set(wmWindow *win, float progress)
Definition: wm_window.c:1825
wmTimer * WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep)
Definition: wm_window.c:1630