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

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

Replacing int with errno_t

The merged code from system-daemon still used the type int
for indicating an error instead of using errno_t. This
commit corrects this mistake

  • Property mode set to 100644
File size: 6.4 KB
Line 
1/*
2 * Copyright (c) 2015 Michal Koutny
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <adt/list.h>
30#include <assert.h>
31#include <errno.h>
32#include <stdlib.h>
33#include <str.h>
34
35#include "repo.h"
36#include "edge.h"
37#include "job.h"
38#include "log.h"
39#include "sysman.h"
40
41/*
42 * Static functions
43 */
44
45/** Remove blocking_job from blocked job structure
46 *
47 * @note Caller must remove blocked_job from collection of blocked_jobs
48 */
49static void job_unblock(job_t *blocked_job, job_t *blocking_job)
50{
51 if (blocking_job->retval == JOB_FAILED) {
52 blocked_job->blocking_job_failed = true;
53 }
54 blocked_job->blocking_jobs -= 1;
55
56 job_del_ref(&blocked_job);
57}
58
59static void job_init(job_t *job, unit_t *u, unit_state_t target_state)
60{
61 assert(job);
62 assert(u);
63 memset(job, 0, sizeof(*job));
64
65 link_initialize(&job->job_queue);
66
67 atomic_store(&job->refcnt, 0);
68
69 job->target_state = target_state;
70 job->unit = u;
71
72 dyn_array_initialize(&job->blocked_jobs, job_t *);
73 job->blocking_jobs = 0;
74 job->blocking_job_failed = false;
75
76 job->state = JOB_EMBRYO;
77 job->retval = JOB_UNDEFINED_;
78}
79
80static bool job_eval_retval(job_t *job)
81{
82 unit_t *u = job->unit;
83
84 if (u->state == job->target_state) {
85 job->retval = JOB_OK;
86 return true;
87 } else if (u->state == STATE_FAILED) {
88 job->retval = JOB_FAILED;
89 return true;
90 } else {
91 return false;
92 }
93}
94
95static void job_check(void *object, void *data)
96{
97 unit_t *u = object;
98 job_t *job = data;
99
100 /*
101 * We have one reference from caller for our disposal,
102 * if needed, pass it to observer.
103 */
104 if (job_eval_retval(job)) {
105 job_finish(job);
106 job_del_ref(&job);
107 } else {
108 // TODO place for timeout
109 sysman_object_observer(u, &job_check, job);
110 }
111}
112
113static void job_destroy(job_t **job_ptr)
114{
115 job_t *job = *job_ptr;
116 if (job == NULL) {
117 return;
118 }
119
120 assert(!link_used(&job->job_queue));
121
122 dyn_array_foreach(job->blocked_jobs, job_t *, job_it) {
123 job_del_ref(&(*job_it));
124 }
125 dyn_array_destroy(&job->blocked_jobs);
126
127 free(job);
128 *job_ptr = NULL;
129}
130
131/*
132 * Non-static functions
133 */
134
135/** Create job assigned to the unit
136 *
137 * @param[in] unit
138 * @param[in] target_state
139 *
140 * @return NULL or newly created job (there is a single refernce for the creator)
141 */
142job_t *job_create(unit_t *u, unit_state_t target_state)
143{
144 job_t *job = malloc(sizeof(job_t));
145 if (job != NULL) {
146 job_init(job, u, target_state);
147
148 /* Add one reference for the creator */
149 job_add_ref(job);
150 }
151
152 return job;
153}
154
155/** Add one reference to job
156 *
157 * Usage:
158 * - adding observer which references the job,
159 * - raising and event that references the job,
160 * - anytime any other new reference is made.
161 */
162void job_add_ref(job_t *job)
163{
164 atomic_fetch_add(&job->refcnt, 1);
165}
166
167/** Remove one reference from job, last remover destroys the job
168 *
169 * Usage:
170 * - inside observer callback that references the job,
171 * - inside event handler that references the job,
172 * - anytime you dispose a reference to the job.
173 */
174void job_del_ref(job_t **job_ptr)
175{
176 job_t *job = *job_ptr;
177
178 assert(job != NULL);
179 assert(atomic_load(&job->refcnt) > 0);
180 atomic_fetch_sub(&job->refcnt, 1);
181 if (atomic_load(&job->refcnt) == 0) {
182 job_destroy(job_ptr);
183 }
184}
185
186void job_run(job_t *job)
187{
188 assert(job->state == JOB_PENDING);
189
190 job->state = JOB_RUNNING;
191 unit_t *u = job->unit;
192 sysman_log(LVL_DEBUG, "%s(%p), %s -> %i",
193 __func__, job, unit_name(u), job->target_state);
194
195 /* Propagate failure */
196 if (job->blocking_job_failed) {
197 goto fail;
198 }
199
200 errno_t rc;
201 // TODO put here similar evaluation as in job_check
202 // goal is to have job_run "idempotent"
203 switch (job->target_state) {
204 case STATE_STARTED:
205 if (u->state == job->target_state) {
206 rc = EOK;
207 } else {
208 rc = unit_start(u);
209 }
210 break;
211 case STATE_STOPPED:
212 if (u->state == job->target_state) {
213 rc = EOK;
214 } else {
215 rc = unit_stop(u);
216 }
217 break;
218 default:
219 assert(false);
220 }
221 if (rc != EOK) {
222 //TODO here is 'rc' value "lost" (not propagated further)
223 sysman_log(LVL_DEBUG, "%s(%p), %s -> %i, error: %i",
224 __func__, job, unit_name(u), job->target_state, rc);
225 goto fail;
226 }
227
228 /*
229 * job_check deletes reference, we want job to remain to caller, thus
230 * add one dummy ref
231 */
232 job_add_ref(job);
233 job_check(job->unit, job);
234 return;
235
236fail:
237 job->retval = JOB_FAILED;
238 job_finish(job);
239}
240
241/** Unblocks blocked jobs and notify observers
242 *
243 * @param[in] job job with defined return value
244 */
245void job_finish(job_t *job)
246{
247 assert(job->state != JOB_FINISHED);
248 assert(job->retval != JOB_UNDEFINED_);
249 assert(!job->unit->job || job->unit->job == job);
250
251 sysman_log(LVL_DEBUG2, "%s(%p) %s ret %i, ref %u",
252 __func__, job, unit_name(job->unit), job->retval,
253 atomic_load(&job->refcnt));
254
255 job->state = JOB_FINISHED;
256
257 /* First remove references, then clear the array */
258 assert(job->blocked_jobs.size == job->blocked_jobs_count);
259 dyn_array_foreach(job->blocked_jobs, job_t *, job_it) {
260 job_unblock(*job_it, job);
261 }
262 dyn_array_clear(&job->blocked_jobs);
263
264 /* Add reference for event handler */
265 if (job->unit->job == NULL) {
266 job_add_ref(job);
267 } else {
268 /* Pass reference from unit */
269 job->unit->job = NULL;
270 }
271 sysman_raise_event(&sysman_event_job_finished, job);
272}
Note: See TracBrowser for help on using the repository browser.