Rizin
unix-like reverse engineering framework and cli tools
task.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2014-2019 pancake <pancake@nopcode.org>
2 // SPDX-FileCopyrightText: 2014-2019 thestr4ng3r <info@florianmaerkl.de>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
5 #include <rz_core.h>
6 
8  RzCoreTaskContextSwitch ctx_switch, void *ctx_switch_user,
9  RzCoreTaskBreak break_cb, void *break_cb_user) {
10  sched->ctx_switch = ctx_switch;
11  sched->ctx_switch_user = ctx_switch_user;
12  sched->break_cb = break_cb;
13  sched->break_cb_user = break_cb_user;
14  sched->task_id_next = 0;
16  sched->tasks_queue = rz_list_new();
18  sched->oneshots_enqueued = 0;
19  sched->lock = rz_th_lock_new(true);
20  sched->tasks_running = 0;
21  sched->oneshot_running = false;
22  sched->main_task = rz_core_task_new(sched, NULL, NULL, NULL);
23  rz_list_append(sched->tasks, sched->main_task);
24  sched->current_task = NULL;
25 }
26 
28  rz_list_free(tasks->tasks);
29  rz_list_free(tasks->tasks_queue);
31  rz_th_lock_free(tasks->lock);
32 }
33 
34 #if HAVE_PTHREAD
35 #define TASK_SIGSET_T sigset_t
36 static void tasks_lock_block_signals(sigset_t *old_sigset) {
37  sigset_t block_sigset;
38  sigemptyset(&block_sigset);
39  sigaddset(&block_sigset, SIGWINCH);
40  rz_signal_sigmask(SIG_BLOCK, &block_sigset, old_sigset);
41 }
42 
43 static void tasks_lock_block_signals_reset(sigset_t *old_sigset) {
44  rz_signal_sigmask(SIG_SETMASK, old_sigset, NULL);
45 }
46 #else
47 #define TASK_SIGSET_T void *
48 static void tasks_lock_block_signals(TASK_SIGSET_T *old_sigset) {
49  (void)old_sigset;
50 }
52  (void)old_sigset;
53 }
54 #endif
55 
56 static void tasks_lock_enter(RzCoreTaskScheduler *scheduler, TASK_SIGSET_T *old_sigset) {
57  tasks_lock_block_signals(old_sigset);
58  rz_th_lock_enter(scheduler->lock);
59 }
60 
61 static void tasks_lock_leave(RzCoreTaskScheduler *scheduler, TASK_SIGSET_T *old_sigset) {
62  rz_th_lock_leave(scheduler->lock);
64 }
65 
66 typedef struct oneshot_t {
67  RzCoreTaskOneShot func;
68  void *user;
70 
73  RzCoreTask *task;
74  int count = 0;
75  TASK_SIGSET_T old_sigset;
76  tasks_lock_enter(scheduler, &old_sigset);
77  rz_list_foreach (scheduler->tasks, iter, task) {
78  if (task != scheduler->main_task && task->state != RZ_CORE_TASK_STATE_DONE) {
79  count++;
80  }
81  }
82  tasks_lock_leave(scheduler, &old_sigset);
83  return count;
84 }
85 
86 static void task_join(RzCoreTask *task) {
87  RzThreadSemaphore *sem = task->running_sem;
88  if (!sem) {
89  return;
90  }
91 
92  rz_th_sem_wait(sem);
93  rz_th_sem_post(sem);
94 }
95 
96 RZ_API void rz_core_task_join(RzCoreTaskScheduler *scheduler, RzCoreTask *current, int id) {
97  if (current && id == current->id) {
98  return;
99  }
100  if (id >= 0) {
101  RzCoreTask *task = rz_core_task_get_incref(scheduler, id);
102  if (!task) {
103  return;
104  }
105  if (current) {
106  rz_core_task_sleep_begin(current);
107  }
108  task_join(task);
109  if (current) {
110  rz_core_task_sleep_end(current);
111  }
112  rz_core_task_decref(task);
113  } else {
114  TASK_SIGSET_T old_sigset;
115  tasks_lock_enter(scheduler, &old_sigset);
116  RzList *tasks = rz_list_clone(scheduler->tasks);
117  RzListIter *iter;
118  RzCoreTask *task;
119  rz_list_foreach (tasks, iter, task) {
120  if (current == task) {
121  continue;
122  }
123  rz_core_task_incref(task);
124  }
125  tasks_lock_leave(scheduler, &old_sigset);
126 
127  rz_list_foreach (tasks, iter, task) {
128  if (current == task) {
129  continue;
130  }
131  if (current) {
132  rz_core_task_sleep_begin(current);
133  }
134  task_join(task);
135  if (current) {
136  rz_core_task_sleep_end(current);
137  }
138  rz_core_task_decref(task);
139  }
140  rz_list_free(tasks);
141  }
142 }
143 
144 static void task_free(RzCoreTask *task) {
145  if (!task) {
146  return;
147  }
148  if (task->runner_free) {
149  task->runner_free(task->runner_user);
150  }
151  if (task->thread) {
152  rz_th_wait(task->thread);
153  rz_th_free(task->thread);
154  }
155  rz_th_sem_free(task->running_sem);
156  rz_th_cond_free(task->dispatch_cond);
157  rz_th_lock_free(task->dispatch_lock);
158  free(task);
159 }
160 
161 RZ_API RzCoreTask *rz_core_task_new(RzCoreTaskScheduler *sched, RzCoreTaskRunner runner, RzCoreTaskRunnerFree runner_free, void *runner_user) {
162  RzCoreTask *task = RZ_NEW0(RzCoreTask);
163  if (!task) {
164  goto fail;
165  }
166 
167  task->sched = sched;
168  task->thread = NULL;
169  task->running_sem = NULL;
170  task->dispatched = false;
171  task->dispatch_cond = rz_th_cond_new();
172  task->dispatch_lock = rz_th_lock_new(false);
173  if (!task->dispatch_cond || !task->dispatch_lock) {
174  goto fail;
175  }
176  task->runner = runner;
177  task->runner_free = runner_free;
178  task->runner_user = runner_user;
179  task->id = sched->task_id_next++;
180  task->state = RZ_CORE_TASK_STATE_BEFORE_START;
181  task->refcount = 1;
182  task->transient = false;
183  return task;
184 
185 fail:
186  task_free(task);
187  return NULL;
188 }
189 
191  if (!task) {
192  return;
193  }
194  TASK_SIGSET_T old_sigset;
195  tasks_lock_enter(task->sched, &old_sigset);
196  task->refcount++;
197  tasks_lock_leave(task->sched, &old_sigset);
198 }
199 
201  if (!task) {
202  return;
203  }
204  TASK_SIGSET_T old_sigset;
205  RzCoreTaskScheduler *sched = task->sched;
206  tasks_lock_enter(sched, &old_sigset);
207  task->refcount--;
208  if (task->refcount <= 0) {
209  task_free(task);
210  }
211  tasks_lock_leave(sched, &old_sigset);
212 }
213 
217 static void cleanup_transient(RzCoreTaskScheduler *sched, RzCoreTask *exclude) {
218  RzCoreTask *ltask;
219  RzListIter *iter;
220  RzListIter *iter_tmp;
221  rz_list_foreach_safe (sched->tasks, iter, iter_tmp, ltask) {
222  if (ltask == exclude) {
223  continue;
224  }
225  if (ltask->transient && ltask->state == RZ_CORE_TASK_STATE_DONE) {
226  rz_list_delete(sched->tasks, iter);
227  }
228  }
229 }
230 
231 RZ_API void rz_core_task_schedule(RzCoreTask *current, RzTaskState next_state) {
232  RzCoreTaskScheduler *sched = current->sched;
233  bool stop = next_state != RZ_CORE_TASK_STATE_RUNNING;
234 
235  if (sched->oneshot_running || (!stop && sched->tasks_running == 1 && sched->oneshots_enqueued == 0)) {
236  return;
237  }
238 
239  sched->current_task = NULL;
240 
241  TASK_SIGSET_T old_sigset;
242  tasks_lock_enter(sched, &old_sigset);
243 
244  current->state = next_state;
245 
246  if (stop) {
247  sched->tasks_running--;
248  }
249 
250  cleanup_transient(sched, current);
251 
252  // oneshots always have priority.
253  // if there are any queued, run them immediately.
254  OneShot *oneshot;
255  while ((oneshot = rz_list_pop_head(sched->oneshot_queue))) {
256  sched->oneshots_enqueued--;
257  sched->oneshot_running = true;
258  oneshot->func(oneshot->user);
259  sched->oneshot_running = false;
260  free(oneshot);
261  }
262 
263  RzCoreTask *next = rz_list_pop_head(sched->tasks_queue);
264 
265  if (next && !stop) {
266  rz_list_append(sched->tasks_queue, current);
267  rz_th_lock_enter(current->dispatch_lock);
268  }
269 
270  tasks_lock_leave(sched, &old_sigset);
271 
272  if (next) {
273  rz_th_lock_enter(next->dispatch_lock);
274  next->dispatched = true;
275  rz_th_lock_leave(next->dispatch_lock);
276  rz_th_cond_signal(next->dispatch_cond);
277  if (!stop) {
278  while (!current->dispatched) {
279  rz_th_cond_wait(current->dispatch_cond, current->dispatch_lock);
280  }
281  current->dispatched = false;
282  rz_th_lock_leave(current->dispatch_lock);
283 
284  tasks_lock_enter(sched, &old_sigset);
285  cleanup_transient(sched, current);
286  tasks_lock_leave(sched, &old_sigset);
287  }
288  }
289 
290  if (!stop) {
291  sched->current_task = current;
292  if (sched->ctx_switch) {
293  sched->ctx_switch(current, sched->ctx_switch_user);
294  }
295  }
296 }
297 
298 static void task_wakeup(RzCoreTask *current) {
299  RzCoreTaskScheduler *sched = current->sched;
300 
301  TASK_SIGSET_T old_sigset;
302  tasks_lock_enter(sched, &old_sigset);
303 
304  sched->tasks_running++;
305  current->state = RZ_CORE_TASK_STATE_RUNNING;
306 
307  // check if there are other tasks running
308  bool single = sched->tasks_running == 1 || sched->tasks_running == 0;
309 
310  rz_th_lock_enter(current->dispatch_lock);
311 
312  // if we are not the only task, we must wait until another task signals us.
313 
314  if (!single) {
315  rz_list_append(sched->tasks_queue, current);
316  }
317 
318  tasks_lock_leave(sched, &old_sigset);
319 
320  if (!single) {
321  while (!current->dispatched) {
322  rz_th_cond_wait(current->dispatch_cond, current->dispatch_lock);
323  }
324  current->dispatched = false;
325  }
326 
327  rz_th_lock_leave(current->dispatch_lock);
328 
329  sched->current_task = current;
330 
331  if (sched->ctx_switch) {
332  sched->ctx_switch(current, sched->ctx_switch_user);
333  }
334 }
335 
337  RzCoreTask *task = rz_core_task_self(scheduler);
338  if (!task) {
339  return;
340  }
341  rz_core_task_schedule(task, RZ_CORE_TASK_STATE_RUNNING);
342 }
343 
344 static void task_end(RzCoreTask *t) {
345  rz_core_task_schedule(t, RZ_CORE_TASK_STATE_DONE);
346 }
347 
348 static void *task_run_thread(RzCoreTask *task) {
349  RzCoreTaskScheduler *sched = task->sched;
350 
351  task_wakeup(task);
352 
353  if (task->breaked) {
354  // breaked in RZ_CORE_TASK_STATE_BEFORE_START
355  goto nonstart;
356  }
357 
358  task->runner(sched, task->runner_user);
359 
360  TASK_SIGSET_T old_sigset;
361 nonstart:
362  tasks_lock_enter(sched, &old_sigset);
363 
364  task_end(task);
365 
366  if (task->running_sem) {
367  rz_th_sem_post(task->running_sem);
368  }
369 
370  tasks_lock_leave(sched, &old_sigset);
371  return NULL;
372 }
373 
375  if (!scheduler || !task) {
376  return;
377  }
378  TASK_SIGSET_T old_sigset;
379  tasks_lock_enter(scheduler, &old_sigset);
380  if (!task->running_sem) {
381  task->running_sem = rz_th_sem_new(1);
382  }
383  if (task->running_sem) {
384  rz_th_sem_wait(task->running_sem);
385  }
386  rz_list_append(scheduler->tasks, task);
387  task->thread = rz_th_new((RzThreadFunction)task_run_thread, task);
388  tasks_lock_leave(scheduler, &old_sigset);
389 }
390 
391 RZ_API void rz_core_task_enqueue_oneshot(RzCoreTaskScheduler *scheduler, RzCoreTaskOneShot func, void *user) {
392  if (!scheduler || !func) {
393  return;
394  }
395  TASK_SIGSET_T old_sigset;
396  tasks_lock_enter(scheduler, &old_sigset);
397  if (scheduler->tasks_running == 0) {
398  // nothing is running right now and no other task can be scheduled
399  // while core->tasks_lock is locked => just run it
400  scheduler->oneshot_running = true;
401  func(user);
402  scheduler->oneshot_running = false;
403  } else {
405  if (oneshot) {
406  oneshot->func = func;
407  oneshot->user = user;
408  rz_list_append(scheduler->oneshot_queue, oneshot);
409  scheduler->oneshots_enqueued++;
410  }
411  }
412  tasks_lock_leave(scheduler, &old_sigset);
413 }
414 
416  task->thread = NULL;
417  return task_run_thread(task) != NULL;
418 }
419 
420 /* begin running stuff synchronously on the main task */
422  RzCoreTask *task = scheduler->main_task;
423  TASK_SIGSET_T old_sigset;
424  tasks_lock_enter(scheduler, &old_sigset);
425  task->thread = NULL;
426  task->state = RZ_CORE_TASK_STATE_BEFORE_START;
427  tasks_lock_leave(scheduler, &old_sigset);
428  task_wakeup(task);
429 }
430 
431 /* end running stuff synchronously, initially started with rz_core_task_sync_begin() */
433  task_end(scheduler->main_task);
434 }
435 
436 /* To be called from within a task.
437  * Begin sleeping and schedule other tasks until rz_core_task_sleep_end() is called. */
439  rz_core_task_schedule(task, RZ_CORE_TASK_STATE_SLEEPING);
440 }
441 
443  task_wakeup(task);
444 }
445 
447  return scheduler->current_task ? scheduler->current_task : scheduler->main_task;
448 }
449 
450 static RzCoreTask *task_get(RzCoreTaskScheduler *scheduler, int id) {
451  RzCoreTask *task;
452  RzListIter *iter;
453  rz_list_foreach (scheduler->tasks, iter, task) {
454  if (task->id == id) {
455  return task;
456  }
457  }
458  return NULL;
459 }
460 
462  TASK_SIGSET_T old_sigset;
463  tasks_lock_enter(scheduler, &old_sigset);
464  RzCoreTask *task = task_get(scheduler, id);
465  if (task) {
466  rz_core_task_incref(task);
467  }
468  tasks_lock_leave(scheduler, &old_sigset);
469  return task;
470 }
471 
475 static void task_break(RzCoreTask *task) {
476  RzCoreTaskScheduler *sched = task->sched;
477  task->breaked = true;
478  if (sched->break_cb) {
479  sched->break_cb(task, sched->break_cb_user);
480  }
481 }
482 
484  TASK_SIGSET_T old_sigset;
485  tasks_lock_enter(scheduler, &old_sigset);
486  RzCoreTask *task = task_get(scheduler, id);
487  if (!task || task->state == RZ_CORE_TASK_STATE_DONE) {
488  tasks_lock_leave(scheduler, &old_sigset);
489  return;
490  }
491  task_break(task);
492  tasks_lock_leave(scheduler, &old_sigset);
493 }
494 
496  TASK_SIGSET_T old_sigset;
497  tasks_lock_enter(scheduler, &old_sigset);
498  RzCoreTask *task;
499  RzListIter *iter;
500  rz_list_foreach (scheduler->tasks, iter, task) {
501  if (task->state != RZ_CORE_TASK_STATE_DONE) {
502  task_break(task);
503  }
504  }
505  tasks_lock_leave(scheduler, &old_sigset);
506 }
507 
508 RZ_API int rz_core_task_del(RzCoreTaskScheduler *scheduler, int id) {
509  RzCoreTask *task;
510  RzListIter *iter;
511  bool ret = false;
512  TASK_SIGSET_T old_sigset;
513  tasks_lock_enter(scheduler, &old_sigset);
514  rz_list_foreach (scheduler->tasks, iter, task) {
515  if (task->id == id) {
516  if (task == scheduler->main_task) {
517  break;
518  }
519  if (task->state == RZ_CORE_TASK_STATE_DONE) {
520  rz_list_delete(scheduler->tasks, iter);
521  } else {
522  task->transient = true;
523  }
524  ret = true;
525  break;
526  }
527  }
528  tasks_lock_leave(scheduler, &old_sigset);
529  return ret;
530 }
531 
532 // above here is for agnostic RzTask api later
533 // -------------------------------------------
534 // below here is for RzCore-specific tasks
535 
540 typedef struct core_task_ctx_t {
544 
545 static bool core_task_ctx_init(CoreTaskCtx *ctx, RzCore *core) {
546  ctx->core = core;
547  ctx->cons_context = rz_cons_context_new(rz_cons_singleton()->context);
548  if (!ctx->cons_context) {
549  return false;
550  }
551  ctx->cons_context->cmd_depth = core->max_cmd_depth;
552  rz_cons_context_break_push(ctx->cons_context, NULL, NULL, false);
553  return true;
554 }
555 
557  if (ctx->cons_context && ctx->cons_context->break_stack) {
558  rz_cons_context_break_pop(ctx->cons_context, false);
559  }
560  rz_cons_context_free(ctx->cons_context);
561 }
562 
566 typedef struct cmd_task_ctx_t {
568  char *cmd;
569  bool cmd_log;
570  char *res;
571  RzCoreCmdTaskFinished finished_cb;
574 
575 static CmdTaskCtx *cmd_task_ctx_new(RzCore *core, const char *cmd, RzCoreCmdTaskFinished finished_cb, void *finished_cb_user) {
578  if (!ctx) {
579  return NULL;
580  }
581  if (!core_task_ctx_init(&ctx->core_ctx, core)) {
582  free(ctx);
583  return NULL;
584  }
585  ctx->cmd = strdup(cmd);
586  ctx->cmd_log = false;
587  ctx->res = NULL;
588  ctx->finished_cb = finished_cb;
589  ctx->finished_cb_user = finished_cb_user;
590  return ctx;
591 }
592 
593 static void cmd_task_runner(RzCoreTaskScheduler *sched, void *user) {
594  CmdTaskCtx *ctx = user;
595  RzCore *core = ctx->core_ctx.core;
596  RzCoreTask *task = rz_core_task_self(sched);
597  char *res_str;
598  if (task == sched->main_task) {
599  rz_core_cmd(core, ctx->cmd, ctx->cmd_log);
600  res_str = NULL;
601  } else {
602  res_str = rz_core_cmd_str(core, ctx->cmd);
603  }
604  ctx->res = res_str;
605 
606  if (ctx->finished_cb) {
607  ctx->finished_cb(res_str, ctx->finished_cb_user);
608  }
609 
610  if (task != sched->main_task && rz_cons_default_context_is_interactive()) {
611  eprintf("\nTask %d finished\n", task->id);
612  }
613 }
614 
615 static void cmd_task_free(CmdTaskCtx *ctx) {
616  if (!ctx) {
617  return;
618  }
619  free(ctx->cmd);
620  free(ctx->res);
621  core_task_ctx_fini(&ctx->core_ctx);
622  free(ctx);
623 }
624 
629 RZ_API RzCoreTask *rz_core_cmd_task_new(RzCore *core, const char *cmd, RzCoreCmdTaskFinished finished_cb, void *finished_cb_user) {
630  CmdTaskCtx *ctx = cmd_task_ctx_new(core, cmd, finished_cb, finished_cb_user);
631  if (!ctx) {
632  return NULL;
633  }
634  RzCoreTask *task = rz_core_task_new(&core->tasks, cmd_task_runner, (RzCoreTaskRunnerFree)cmd_task_free, ctx);
635  if (!task) {
637  return NULL;
638  }
639  return task;
640 }
641 
647  // Check if this is really a command task
648  if (!task->runner_user || task->runner != cmd_task_runner) {
649  return NULL;
650  }
651  CmdTaskCtx *ctx = task->runner_user;
652  return ctx->res;
653 }
654 
658 typedef struct function_task_ctx_t {
660  RzCoreTaskFunction fcn;
661  void *fcn_user;
662  void *res;
664 
665 static FunctionTaskCtx *function_task_ctx_new(RzCore *core, RzCoreTaskFunction fcn, void *fcn_user) {
667  if (!ctx) {
668  return NULL;
669  }
670  if (!core_task_ctx_init(&ctx->core_ctx, core)) {
671  free(ctx);
672  return NULL;
673  }
674  ctx->fcn = fcn;
675  ctx->fcn_user = fcn_user;
676  ctx->res = NULL;
677  return ctx;
678 }
679 
680 static void function_task_runner(RzCoreTaskScheduler *sched, void *user) {
681  FunctionTaskCtx *ctx = user;
682  RzCore *core = ctx->core_ctx.core;
683  rz_cons_push();
684  ctx->res = ctx->fcn(core, ctx->fcn_user);
685  rz_cons_pop();
686 }
687 
689  if (!ctx) {
690  return;
691  }
692  core_task_ctx_fini(&ctx->core_ctx);
693  free(ctx);
694 }
695 
700 RZ_API RzCoreTask *rz_core_function_task_new(RzCore *core, RzCoreTaskFunction fcn, void *fcn_user) {
701  FunctionTaskCtx *ctx = function_task_ctx_new(core, fcn, fcn_user);
702  if (!ctx) {
703  return NULL;
704  }
706  (RzCoreTaskRunnerFree)function_task_free, ctx);
707  if (!task) {
709  return NULL;
710  }
711  return task;
712 }
713 
719  // Check if this is really a command task
720  if (!task->runner_user || task->runner != function_task_runner) {
721  return NULL;
722  }
723  FunctionTaskCtx *ctx = task->runner_user;
724  return ctx->res;
725 }
726 
727 RZ_IPI void rz_core_task_ctx_switch(RzCoreTask *next, void *user) {
728  if (next->runner_user) {
729  CoreTaskCtx *ctx = next->runner_user;
730  if (ctx->cons_context) {
731  rz_cons_context_load(ctx->cons_context);
732  return;
733  }
734  }
736 }
737 
738 RZ_IPI void rz_core_task_break_cb(RzCoreTask *task, void *user) {
739  CoreTaskCtx *ctx = task->runner_user;
740  rz_cons_context_break(ctx ? ctx->cons_context : NULL);
741 }
742 
744  switch (task->state) {
745  case RZ_CORE_TASK_STATE_RUNNING:
746  return "running";
747  case RZ_CORE_TASK_STATE_SLEEPING:
748  return "sleeping";
749  case RZ_CORE_TASK_STATE_DONE:
750  return "done";
751  case RZ_CORE_TASK_STATE_BEFORE_START:
752  return "before start";
753  default:
754  return "unknown";
755  }
756 }
757 
758 RZ_API void rz_core_task_print(RzCore *core, RzCoreTask *task, int mode, PJ *j) {
759  rz_return_if_fail(mode != 'j' || j);
760  if (task != core->tasks.main_task && task->runner != cmd_task_runner) {
761  // don't print tasks that are custom function-runners, which come from internal code.
762  // only main and command ones, which should be user-visible.
763  return;
764  }
765  const char *cmd = NULL;
766  if (task != core->tasks.main_task) {
767  cmd = ((CmdTaskCtx *)task->runner_user)->cmd;
768  }
769  switch (mode) {
770  case 'j': {
771  pj_o(j);
772  pj_ki(j, "id", task->id);
773  const char *state;
774  // This is NOT the same as rz_core_task_status()!
775  // rz_core_task_status() is meant to be readable and may be changed.
776  // These are meant to be stable for scripting.
777  switch (task->state) {
778  case RZ_CORE_TASK_STATE_BEFORE_START:
779  state = "before_start";
780  break;
781  case RZ_CORE_TASK_STATE_RUNNING:
782  state = "running";
783  break;
784  case RZ_CORE_TASK_STATE_SLEEPING:
785  state = "sleeping";
786  break;
787  case RZ_CORE_TASK_STATE_DONE:
788  state = "done";
789  break;
790  default:
791  state = "invalid";
792  }
793  pj_ks(j, "state", state);
794  pj_kb(j, "transient", task->transient);
795  if (cmd) {
796  pj_ks(j, "cmd", cmd);
797  }
798  pj_end(j);
799  break;
800  default: {
801  rz_cons_printf("%3d %3s %12s %s\n",
802  task->id,
803  task->transient ? "(t)" : "",
804  rz_core_task_status(task),
805  cmd ? cmd : "-- MAIN TASK --");
806  } break;
807  }
808  }
809 }
810 
812  RzListIter *iter;
813  RzCoreTask *task;
814  PJ *j = NULL;
815  if (mode == 'j') {
816  j = pj_new();
817  pj_a(j);
818  }
819  TASK_SIGSET_T old_sigset;
820  tasks_lock_enter(&core->tasks, &old_sigset);
821  rz_list_foreach (core->tasks.tasks, iter, task) {
822  rz_core_task_print(core, task, mode, j);
823  }
824  if (j) {
825  pj_end(j);
827  pj_free(j);
828  } else {
829  rz_cons_printf("--\ntotal running: %d\n", core->tasks.tasks_running);
830  }
831  tasks_lock_leave(&core->tasks, &old_sigset);
832 }
833 
834 RZ_API bool rz_core_task_is_cmd(RzCore *core, int id) {
835  RzCoreTask *task = rz_core_task_get_incref(&core->tasks, id);
836  if (!task) {
837  return false;
838  }
839  bool r = task->runner == cmd_task_runner;
840  rz_core_task_decref(task);
841  return r;
842 }
843 
845  TASK_SIGSET_T old_sigset;
846  tasks_lock_enter(&core->tasks, &old_sigset);
847  RzCoreTaskScheduler *sched = &core->tasks;
848  RzCoreTask *task;
849  RzListIter *iter, *iter2;
850  rz_list_foreach_safe (sched->tasks, iter, iter2, task) {
851  if (task != sched->main_task && task->state == RZ_CORE_TASK_STATE_DONE && task->runner == cmd_task_runner) {
852  rz_list_delete(sched->tasks, iter);
853  }
854  }
855  tasks_lock_leave(&core->tasks, &old_sigset);
856 }
#define RZ_IPI
Definition: analysis_wasm.c:11
static RzBinXtrData * oneshot(RzBin *bin, const ut8 *buf, ut64 size, int subbin_type)
RZ_API int rz_core_cmd(RzCore *core, const char *cstr, int log)
Definition: cmd.c:5328
RZ_API char * rz_core_cmd_str(RzCore *core, const char *cmd)
Executes a rizin command and returns the stdout as a string.
Definition: cmd.c:5513
RZ_API bool rz_cons_default_context_is_interactive(void)
Definition: cons.c:369
RZ_API void rz_cons_context_free(RzConsContext *context)
Definition: cons.c:897
RZ_API RzConsContext * rz_cons_context_new(RZ_NULLABLE RzConsContext *parent)
Definition: cons.c:888
RZ_API void rz_cons_context_reset(void)
Definition: cons.c:909
RZ_API RzCons * rz_cons_singleton(void)
Definition: cons.c:300
RZ_API void rz_cons_context_break(RzConsContext *context)
Definition: cons.c:917
RZ_API int rz_cons_printf(const char *format,...)
Definition: cons.c:1202
RZ_API void rz_cons_context_break_pop(RzConsContext *context, bool sig)
Definition: cons.c:335
RZ_API void rz_cons_context_load(RzConsContext *context)
Definition: cons.c:905
RZ_API void rz_cons_println(const char *str)
Definition: cons.c:233
RZ_API void rz_cons_context_break_push(RzConsContext *context, RzConsBreak cb, void *user, bool sig)
Definition: cons.c:308
RZ_API void rz_cons_pop(void)
Definition: cons.c:876
RZ_API void rz_cons_push(void)
Definition: cons.c:860
#define RZ_API
#define NULL
Definition: cris-opc.c:27
#define r
Definition: crypto_rc6.c:12
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
Definition: sflib.h:98
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags cmd
Definition: sflib.h:79
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
const char int mode
Definition: ioapi.h:137
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
Definition: list.c:248
RZ_API void rz_list_delete(RZ_NONNULL RzList *list, RZ_NONNULL RzListIter *iter)
Removes an entry in the list by using the RzListIter pointer.
Definition: list.c:162
RZ_API RZ_OWN RzList * rz_list_clone(RZ_NONNULL const RzList *list)
Shallow copies of the list (but doesn't free its elements)
Definition: list.c:496
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API RZ_OWN void * rz_list_pop_head(RZ_NONNULL RzList *list)
Removes and returns the first element of the list.
Definition: list.c:401
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
RZ_API void rz_th_free(RZ_NULLABLE RzThread *th)
Frees a RzThread structure.
Definition: thread.c:246
RZ_API RZ_OWN RzThread * rz_th_new(RZ_NONNULL RzThreadFunction function, RZ_NULLABLE void *user)
Creates and starts a new thread.
Definition: thread.c:198
RZ_API bool rz_th_wait(RZ_NONNULL RzThread *th)
Awaits indefinetely for a thread to join.
Definition: thread.c:231
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
#define eprintf(x, y...)
Definition: rlcc.c:7
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
void(* RzCoreTaskContextSwitch)(RzCoreTask *next, void *user)
Definition: rz_core.h:259
struct rz_core_task_t RzCoreTask
Definition: rz_core.h:254
void(* RzCoreTaskBreak)(RzCoreTask *task, void *user)
Definition: rz_core.h:264
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
RZ_API PJ * pj_new(void)
Definition: pj.c:25
RZ_API PJ * pj_kb(PJ *j, const char *k, bool v)
Definition: pj.c:177
RZ_API PJ * pj_ki(PJ *j, const char *k, int d)
Definition: pj.c:149
RZ_API PJ * pj_end(PJ *j)
Definition: pj.c:87
RZ_API const char * pj_string(PJ *pj)
Definition: pj.c:57
RZ_API void pj_free(PJ *j)
Definition: pj.c:34
RZ_API PJ * pj_o(PJ *j)
Definition: pj.c:75
RZ_API PJ * pj_ks(PJ *j, const char *k, const char *v)
Definition: pj.c:170
RZ_API PJ * pj_a(PJ *j)
Definition: pj.c:81
void *(* RzThreadFunction)(void *user)
Definition: rz_th.h:28
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_NEW(x)
Definition: rz_types.h:285
int sigset_t
Definition: sftypes.h:63
char * res
Definition: task.c:570
CoreTaskCtx core_ctx
Definition: task.c:567
void * finished_cb_user
Definition: task.c:572
RzCoreCmdTaskFinished finished_cb
Definition: task.c:571
bool cmd_log
Definition: task.c:569
char * cmd
Definition: task.c:568
RzConsContext * cons_context
Definition: task.c:542
RzCore * core
Definition: task.c:541
void * fcn_user
Definition: task.c:661
RzCoreTaskFunction fcn
Definition: task.c:660
CoreTaskCtx core_ctx
Definition: task.c:659
Definition: task.c:66
void * user
Definition: task.c:68
RzCoreTaskOneShot func
Definition: task.c:67
Definition: rz_pj.h:12
int max_cmd_depth
Definition: rz_core.h:363
RzCoreTaskScheduler tasks
Definition: rz_core.h:362
int oneshots_enqueued
Definition: rz_core.h:275
RzThreadLock * lock
Definition: rz_core.h:278
RzList * tasks_queue
Definition: rz_core.h:273
RzCoreTaskContextSwitch ctx_switch
Definition: rz_core.h:267
void * ctx_switch_user
Definition: rz_core.h:268
int tasks_running
Definition: rz_core.h:279
RzCoreTaskBreak break_cb
Definition: rz_core.h:269
bool oneshot_running
Definition: rz_core.h:280
RzList * tasks
Definition: rz_core.h:272
struct rz_core_task_t * current_task
Definition: rz_core.h:276
RzList * oneshot_queue
Definition: rz_core.h:274
void * break_cb_user
Definition: rz_core.h:270
int task_id_next
Definition: rz_core.h:271
struct rz_core_task_t * main_task
Definition: rz_core.h:277
Definition: dis.h:43
RZ_API bool rz_core_task_is_cmd(RzCore *core, int id)
Definition: task.c:834
static void tasks_lock_enter(RzCoreTaskScheduler *scheduler, TASK_SIGSET_T *old_sigset)
Definition: task.c:56
static void function_task_free(FunctionTaskCtx *ctx)
Definition: task.c:688
RZ_API void rz_core_task_join(RzCoreTaskScheduler *scheduler, RzCoreTask *current, int id)
Definition: task.c:96
RZ_API void rz_core_task_scheduler_init(RzCoreTaskScheduler *sched, RzCoreTaskContextSwitch ctx_switch, void *ctx_switch_user, RzCoreTaskBreak break_cb, void *break_cb_user)
Definition: task.c:7
RZ_API RzCoreTask * rz_core_task_new(RzCoreTaskScheduler *sched, RzCoreTaskRunner runner, RzCoreTaskRunnerFree runner_free, void *runner_user)
Definition: task.c:161
RZ_API void rz_core_task_decref(RzCoreTask *task)
Definition: task.c:200
static FunctionTaskCtx * function_task_ctx_new(RzCore *core, RzCoreTaskFunction fcn, void *fcn_user)
Definition: task.c:665
RZ_API void rz_core_task_schedule(RzCoreTask *current, RzTaskState next_state)
Definition: task.c:231
static void tasks_lock_leave(RzCoreTaskScheduler *scheduler, TASK_SIGSET_T *old_sigset)
Definition: task.c:61
RZ_API void rz_core_task_break_all(RzCoreTaskScheduler *scheduler)
Definition: task.c:495
static bool core_task_ctx_init(CoreTaskCtx *ctx, RzCore *core)
Definition: task.c:545
static void tasks_lock_block_signals_reset(TASK_SIGSET_T *old_sigset)
Definition: task.c:51
RZ_API void rz_core_task_sync_end(RzCoreTaskScheduler *scheduler)
Definition: task.c:432
RZ_API void rz_core_task_scheduler_fini(RzCoreTaskScheduler *tasks)
Definition: task.c:27
RZ_API void rz_core_task_print(RzCore *core, RzCoreTask *task, int mode, PJ *j)
Definition: task.c:758
static void core_task_ctx_fini(CoreTaskCtx *ctx)
Definition: task.c:556
RZ_API void rz_core_task_enqueue_oneshot(RzCoreTaskScheduler *scheduler, RzCoreTaskOneShot func, void *user)
Definition: task.c:391
RZ_IPI void rz_core_task_ctx_switch(RzCoreTask *next, void *user)
Definition: task.c:727
struct core_task_ctx_t CoreTaskCtx
RZ_API void rz_core_task_sleep_end(RzCoreTask *task)
Definition: task.c:442
#define TASK_SIGSET_T
Definition: task.c:47
static void cmd_task_runner(RzCoreTaskScheduler *sched, void *user)
Definition: task.c:593
static void task_end(RzCoreTask *t)
Definition: task.c:344
RZ_API void rz_core_task_incref(RzCoreTask *task)
Definition: task.c:190
struct cmd_task_ctx_t CmdTaskCtx
struct function_task_ctx_t FunctionTaskCtx
RZ_API int rz_core_task_del(RzCoreTaskScheduler *scheduler, int id)
Definition: task.c:508
static void cleanup_transient(RzCoreTaskScheduler *sched, RzCoreTask *exclude)
Definition: task.c:217
RZ_API void rz_core_task_del_all_done(RzCore *core)
Definition: task.c:844
static void * task_run_thread(RzCoreTask *task)
Definition: task.c:348
static void cmd_task_free(CmdTaskCtx *ctx)
Definition: task.c:615
RZ_API int rz_core_task_running_tasks_count(RzCoreTaskScheduler *scheduler)
Definition: task.c:71
static RzCoreTask * task_get(RzCoreTaskScheduler *scheduler, int id)
Definition: task.c:450
RZ_API int rz_core_task_run_sync(RzCoreTaskScheduler *scheduler, RzCoreTask *task)
Definition: task.c:415
RZ_API RzCoreTask * rz_core_function_task_new(RzCore *core, RzCoreTaskFunction fcn, void *fcn_user)
Definition: task.c:700
RZ_API void rz_core_task_enqueue(RzCoreTaskScheduler *scheduler, RzCoreTask *task)
Definition: task.c:374
struct oneshot_t OneShot
RZ_API RzCoreTask * rz_core_task_get_incref(RzCoreTaskScheduler *scheduler, int id)
Definition: task.c:461
RZ_API RzCoreTask * rz_core_cmd_task_new(RzCore *core, const char *cmd, RzCoreCmdTaskFinished finished_cb, void *finished_cb_user)
Definition: task.c:629
static void function_task_runner(RzCoreTaskScheduler *sched, void *user)
Definition: task.c:680
RZ_API void rz_core_task_list(RzCore *core, int mode)
Definition: task.c:811
static void task_join(RzCoreTask *task)
Definition: task.c:86
RZ_API void rz_core_task_sleep_begin(RzCoreTask *task)
Definition: task.c:438
static CmdTaskCtx * cmd_task_ctx_new(RzCore *core, const char *cmd, RzCoreCmdTaskFinished finished_cb, void *finished_cb_user)
Definition: task.c:575
RZ_API void rz_core_task_yield(RzCoreTaskScheduler *scheduler)
Definition: task.c:336
static void task_wakeup(RzCoreTask *current)
Definition: task.c:298
RZ_API const char * rz_core_cmd_task_get_result(RzCoreTask *task)
Definition: task.c:646
RZ_API void rz_core_task_sync_begin(RzCoreTaskScheduler *scheduler)
Definition: task.c:421
RZ_IPI void rz_core_task_break_cb(RzCoreTask *task, void *user)
Definition: task.c:738
RZ_API void rz_core_task_break(RzCoreTaskScheduler *scheduler, int id)
Definition: task.c:483
RZ_API RzCoreTask * rz_core_task_self(RzCoreTaskScheduler *scheduler)
Definition: task.c:446
static void tasks_lock_block_signals(TASK_SIGSET_T *old_sigset)
Definition: task.c:48
RZ_API void * rz_core_function_task_get_result(RzCoreTask *task)
Definition: task.c:718
RZ_API const char * rz_core_task_status(RzCoreTask *task)
Definition: task.c:743
static void task_break(RzCoreTask *task)
Definition: task.c:475
static void task_free(RzCoreTask *task)
Definition: task.c:144
#define fail(test)
Definition: tests.h:29
RZ_API void rz_th_cond_free(RZ_NULLABLE RzThreadCond *cond)
Frees a RzThreadCond struct.
Definition: thread_cond.c:77
RZ_API void rz_th_cond_signal(RZ_NONNULL RzThreadCond *cond)
This function shall unblock at least one of the threads that are blocked on the specified condition.
Definition: thread_cond.c:34
RZ_API void rz_th_cond_wait(RZ_NONNULL RzThreadCond *cond, RZ_NONNULL RzThreadLock *lock)
The function shall block on a condition variable and shall be called with RzThreadLock locked by the ...
Definition: thread_cond.c:63
RZ_API RZ_OWN RzThreadCond * rz_th_cond_new(void)
Condition variables are intended to be used to communicate changes in the state of data shared betwee...
Definition: thread_cond.c:13
RZ_API void rz_th_lock_leave(RZ_NONNULL RzThreadLock *thl)
Releases a RzThreadLock structure.
Definition: thread_lock.c:75
RZ_API void rz_th_lock_free(RZ_NULLABLE RzThreadLock *thl)
Frees a RzThreadLock structure.
Definition: thread_lock.c:89
RZ_API RZ_OWN RzThreadLock * rz_th_lock_new(bool recursive)
Allocates and initialize a RzThreadLock structure.
Definition: thread_lock.c:14
RZ_API void rz_th_lock_enter(RZ_NONNULL RzThreadLock *thl)
Acquires a RzThreadLock structure.
Definition: thread_lock.c:45
RZ_API RZ_OWN RzThreadSemaphore * rz_th_sem_new(unsigned int initial)
Allocates and initialize a RzThreadSemaphore structure.
Definition: thread_sem.c:26
RZ_API void rz_th_sem_free(RZ_NULLABLE RzThreadSemaphore *sem)
Frees a RzThreadSemaphore struct.
Definition: thread_sem.c:73
RZ_API void rz_th_sem_post(RZ_NONNULL RzThreadSemaphore *sem)
increments (releases) a semaphore
Definition: thread_sem.c:97
RZ_API void rz_th_sem_wait(RZ_NONNULL RzThreadSemaphore *sem)
Decrements (acquires) the semaphore (waits indefinetely)
Definition: thread_sem.c:111
#define SIGWINCH
Definition: win.h:88