fb99892c066964ba71843140b254ac450199180c
[oweals/libubox.git] / tests / test-runqueue.c
1 /*
2  * runqueue-example.c
3  *
4  * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18
19 #include <stdbool.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <unistd.h>
23
24 #include "uloop.h"
25 #include "runqueue.h"
26
27 static struct runqueue q;
28
29 struct sleeper {
30         int val;
31         bool kill;
32         struct uloop_timeout t;
33         struct runqueue_process proc;
34 };
35
36 static void q_empty(struct runqueue *q)
37 {
38         fprintf(stderr, "All done!\n");
39         uloop_end();
40 }
41
42 static const char* sleeper_type(struct sleeper *s)
43 {
44         return s->kill ? "killer" : "sleeper";
45 }
46
47 static void q_sleep_run(struct runqueue *q, struct runqueue_task *t)
48 {
49         struct sleeper *s = container_of(t, struct sleeper, proc.task);
50         char str[32];
51         pid_t pid;
52
53         fprintf(stderr, "[%d/%d] start 'sleep %d' (%s)\n", q->running_tasks,
54                         q->max_running_tasks, s->val, sleeper_type(s));
55
56         pid = fork();
57         if (pid < 0)
58                 return;
59
60         if (pid) {
61                 runqueue_process_add(q, &s->proc, pid);
62                 return;
63         }
64
65         sprintf(str, "%d", s->val);
66         execlp("sleep", "sleep", str, NULL);
67         exit(1);
68 }
69
70 static void q_sleep_cancel(struct runqueue *q, struct runqueue_task *t, int type)
71 {
72         struct sleeper *s = container_of(t, struct sleeper, proc.task);
73
74         fprintf(stderr, "[%d/%d] cancel 'sleep %d' (%s)\n", q->running_tasks,
75                         q->max_running_tasks, s->val, sleeper_type(s));
76         runqueue_process_cancel_cb(q, t, type);
77 }
78
79 static void q_sleep_complete(struct runqueue *q, struct runqueue_task *p)
80 {
81         struct sleeper *s = container_of(p, struct sleeper, proc.task);
82
83         fprintf(stderr, "[%d/%d] finish 'sleep %d' (%s) \n", q->running_tasks,
84                         q->max_running_tasks, s->val, sleeper_type(s));
85         free(s);
86 }
87
88 static void my_runqueue_process_kill_cb(struct runqueue *q, struct runqueue_task *p)
89 {
90         struct sleeper *s = container_of(p, struct sleeper, proc.task);
91
92         fprintf(stderr, "[%d/%d] killing process (%s)\n", q->running_tasks,
93                         q->max_running_tasks, sleeper_type(s));
94         runqueue_process_kill_cb(q, p);
95 }
96
97 static void timer_cb(struct uloop_timeout *t)
98 {
99         struct sleeper *s = container_of(t, struct sleeper, t);
100         if (s->kill)
101                 runqueue_task_kill(&s->proc.task);
102 }
103
104 static struct sleeper* create_sleeper(int val, const struct runqueue_task_type *type, bool kill)
105 {
106         struct sleeper *s = calloc(1, sizeof(*s));
107         s->kill = kill;
108         s->t.cb = timer_cb;
109         s->proc.task.type = type;
110         s->proc.task.run_timeout = 500;
111         s->proc.task.complete = q_sleep_complete;
112         s->val = val;
113
114         return s;
115 }
116
117 static void add_sleeper(int val)
118 {
119         static const struct runqueue_task_type sleeper_type = {
120                 .run = q_sleep_run,
121                 .cancel = q_sleep_cancel,
122                 .kill = runqueue_process_kill_cb,
123         };
124
125         static const struct runqueue_task_type killer_type = {
126                 .run = q_sleep_run,
127                 .cancel = q_sleep_cancel,
128                 .kill = my_runqueue_process_kill_cb,
129         };
130
131         struct sleeper *k = create_sleeper(val, &killer_type, true);
132         uloop_timeout_set(&k->t, 100);
133         uloop_timeout_add(&k->t);
134         runqueue_task_add(&q, &k->proc.task, false);
135
136         struct sleeper *s = create_sleeper(val, &sleeper_type, false);
137         runqueue_task_add(&q, &s->proc.task, false);
138 }
139
140 int main(int argc, char **argv)
141 {
142         uloop_init();
143
144         runqueue_init(&q);
145         q.empty_cb = q_empty;
146         q.max_running_tasks = 1;
147
148         if (argc > 1)
149                 q.max_running_tasks = atoi(argv[1]);
150
151         add_sleeper(1);
152         add_sleeper(1);
153         add_sleeper(1);
154
155         uloop_run();
156         uloop_done();
157
158         return 0;
159 }