source: mainline/uspace/srv/sysman/job.c@ 694253c

Last change on this file since 694253c was 694253c, checked in by Matthieu Riolo <matthieu.riolo@…>, 6 years ago

Skeleton for sysman (unit) jobs control

  • Property mode set to 100644
File size: 4.0 KB
Line 
1#include <adt/list.h>
2#include <assert.h>
3#include <errno.h>
4#include <fibril.h>
5#include <fibril_synch.h>
6#include <stdio.h>
7#include <stdlib.h>
8
9#include "job.h"
10#include "unit.h"
11
12static list_t job_queue;
13static fibril_mutex_t job_queue_mtx;
14static fibril_condvar_t job_queue_cv;
15
16static int job_run_start(job_t *job)
17{
18 unit_t *unit = job->unit;
19
20 int rc = unit_start(unit);
21 if (rc != EOK) {
22 return rc;
23 }
24
25 fibril_mutex_lock(&unit->state_mtx);
26 while (unit->state != STATE_STARTED) {
27 fibril_condvar_wait(&unit->state_cv, &unit->state_mtx);
28 }
29 fibril_mutex_unlock(&unit->state_mtx);
30
31 // TODO react to failed state
32 return EOK;
33}
34
35static int job_runner(void *arg)
36{
37 job_t *job = (job_t *)arg;
38
39 int retval = EOK;
40
41 /* Wait for previous jobs */
42 list_foreach(job->blocking_jobs, link, job_link_t, jl) {
43 retval = job_wait(jl->job);
44 if (retval != EOK) {
45 break;
46 }
47 }
48
49 if (retval != EOK) {
50 goto finish;
51 }
52
53 /* Run the job itself */
54 fibril_mutex_lock(&job->state_mtx);
55 job->state = JOB_RUNNING;
56 fibril_condvar_broadcast(&job->state_cv);
57 fibril_mutex_unlock(&job->state_mtx);
58
59 switch (job->type) {
60 case JOB_START:
61 retval = job_run_start(job);
62 break;
63 default:
64 assert(false);
65 }
66
67
68finish:
69 fibril_mutex_lock(&job->state_mtx);
70 job->state = JOB_FINISHED;
71 job->retval = retval;
72 fibril_condvar_broadcast(&job->state_cv);
73 fibril_mutex_unlock(&job->state_mtx);
74
75 return EOK;
76}
77
78static int job_dispatcher(void *arg)
79{
80 fibril_mutex_lock(&job_queue_mtx);
81 while (1) {
82 while (list_empty(&job_queue)) {
83 fibril_condvar_wait(&job_queue_cv, &job_queue_mtx);
84 }
85
86 link_t *link = list_first(&job_queue);
87 assert(link);
88 list_remove(link);
89
90 /*
91 * Note that possible use of fibril pool must hold invariant
92 * that job is started asynchronously. In the case there exists
93 * circular dependency between jobs, it may attain a deadlock.
94 */
95 job_t *job = list_get_instance(link, job_t, link);
96 fid_t runner_fibril = fibril_create(job_runner, job); // TODO cast to void*?
97 fibril_add_ready(runner_fibril);
98 }
99
100 fibril_mutex_unlock(&job_queue_mtx);
101 return EOK;
102}
103
104void job_queue_init()
105{
106 list_initialize(&job_queue);
107 fibril_mutex_initialize(&job_queue_mtx);
108 fibril_condvar_initialize(&job_queue_cv);
109
110 fid_t dispatcher_fibril = fibril_create(job_dispatcher, NULL);
111 fibril_add_ready(dispatcher_fibril);
112}
113
114int job_queue_jobs(list_t *jobs)
115{
116 fibril_mutex_lock(&job_queue_mtx);
117
118 /* Check consistency with queue. */
119 list_foreach(*jobs, link, job_t, new_job) {
120 list_foreach(job_queue, link, job_t, queued_job) {
121 /*
122 * Currently we have strict strategy not permitting
123 * multiple jobs for one unit in the queue.
124 */
125 if (new_job->unit == queued_job->unit) {
126 return EEXIST;
127 }
128 }
129 }
130
131 /* Enqueue jobs */
132 list_foreach_safe(*jobs, cur_link, next_lin) {
133 list_remove(cur_link);
134 list_append(cur_link, &job_queue);
135 }
136
137 fibril_condvar_signal(&job_queue_cv);
138 fibril_mutex_unlock(&job_queue_mtx);
139
140 return EOK;
141}
142
143/** Blocking wait for job finishing.
144 *
145 * Multiple fibrils may wait for the same job.
146 *
147 * @return Return code of the job
148 */
149int job_wait(job_t *job)
150{
151 fibril_mutex_lock(&job->state_mtx);
152 while (job->state != JOB_FINISHED) {
153 fibril_condvar_wait(&job->state_cv, &job->state_mtx);
154 }
155
156 int rc = job->retval;
157 fibril_mutex_unlock(&job->state_mtx);
158
159 return rc;
160}
161
162static void job_init(job_t *job, job_type_t type)
163{
164 assert(job);
165
166 link_initialize(&job->link);
167 list_initialize(&job->blocking_jobs);
168
169 job->type = type;
170 job->unit = NULL;
171
172 job->state = JOB_WAITING;
173 fibril_mutex_initialize(&job->state_mtx);
174 fibril_condvar_initialize(&job->state_cv);
175}
176
177job_t *job_create(job_type_t type)
178{
179 job_t *job = malloc(sizeof(job_t));
180 if (job != NULL) {
181 job_init(job, type);
182 }
183
184 return job;
185}
186
187void job_destroy(job_t **job_ptr)
188{
189 job_t *job = *job_ptr;
190 if (job == NULL) {
191 return;
192 }
193
194 list_foreach_safe(job->blocking_jobs, cur_link, next_link) {
195 job_link_t *jl = list_get_instance(cur_link, job_link_t, link);
196 list_remove(cur_link);
197 free(jl);
198 }
199 free(job);
200
201 *job_ptr = NULL;
202}
Note: See TracBrowser for help on using the repository browser.