source: mainline/uspace/srv/sysman/sm_task.c@ 13b4504

Last change on this file since 13b4504 was 3529f148, checked in by Matthieu Riolo <matthieu.riolo@…>, 5 years ago

Adding types task_wait_flag_t and ipc_start_flag_t which replaces makros

  • Property mode set to 100644
File size: 5.5 KB
RevLine 
[e8747bd8]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>
[8ae8262]30#include <errno.h>
[e8747bd8]31#include <stdlib.h>
32#include <task.h>
[8ae8262]33#include <sysman/unit.h>
[e8747bd8]34
[af92309]35#include "repo.h"
[e8747bd8]36#include "log.h"
37#include "sysman.h"
38#include "sm_task.h"
39
40/** Structure for boxing task event */
41struct sm_task_event {
42 task_id_t task_id;
[3529f148]43 task_wait_flag_t flags;
[e8747bd8]44 task_exit_t texit;
45 int retval;
46};
47
48static void sysman_event_task_event(void *);
49
50/**
51 * @note This function runs in separate fibril (not same as event loop).
52 */
[3529f148]53static void sm_task_event_handler(task_id_t tid, task_wait_flag_t flags, task_exit_t texit,
[e8747bd8]54 int retval)
55{
56 sm_task_event_t *tev = malloc(sizeof(sm_task_event_t));
57 if (tev == NULL) {
58 sysman_log(LVL_FATAL,
59 "Unable to process event of task %" PRIu64 ".", tid);
60 return;
61 }
62 tev->task_id = tid;
63 tev->flags = flags;
64 tev->texit = texit;
65 tev->retval = retval;
66
67 sysman_raise_event(&sysman_event_task_event, tev);
68}
69
70static unit_svc_t *sm_task_find_service(task_id_t tid)
71{
72 /*
73 * Unit to task is about to be developed, so use plain linear search
74 * instead of specialized structures.
75 */
[015b147]76 repo_foreach_t(UNIT_SERVICE, u) {
[e8747bd8]77 if (CAST_SVC(u)->main_task_id == tid) {
78 return CAST_SVC(u);
79 }
80
81 }
82
83 return NULL;
84}
85
[8ae8262]86static unit_svc_t *sm_task_create_service(task_id_t tid)
87{
88 unit_t *u_svc = unit_create(UNIT_SERVICE);
89 bool in_repo_update = false;
[25697163]90 errno_t rc = EOK;
[8ae8262]91
92 if (u_svc == NULL) {
93 goto fail;
94 }
95
96 rc = asprintf(&u_svc->name, ANONYMOUS_SERVICE_MASK "%c%s", tid,
97 UNIT_NAME_SEPARATOR, UNIT_SVC_TYPE_NAME);
98 if (rc < 0) {
99 goto fail;
100 }
101
102 CAST_SVC(u_svc)->main_task_id = tid;
103 CAST_SVC(u_svc)->anonymous = true;
[102f641]104 /*
105 * exec_start is left undefined, maybe could be hinted by kernel's task
106 * name
107 */
[8ae8262]108
[8d74fdd]109 /*
110 * Temporary workaround to avoid killing ourselves during shutdown,
111 * eventually should be captured by dependencies.
112 */
113 if (tid == task_get_id() || tid == 2 /*taskman*/) {
114 CAST_SVC(u_svc)->critical = true;
115 }
116
[8ae8262]117 repo_begin_update();
118 in_repo_update = true;
119
120 rc = repo_add_unit(u_svc);
121 if (rc != EOK) {
122 goto fail;
123 }
124
125 repo_commit();
126
127 return CAST_SVC(u_svc);
[102f641]128
[8ae8262]129fail:
130 if (in_repo_update) {
131 repo_rollback();
132 }
133
134 unit_destroy(&u_svc);
135 return NULL;
136}
137
138static void sm_task_delete_service(unit_svc_t *u_svc)
139{
140 repo_begin_update();
[25697163]141 errno_t rc = repo_remove_unit(&u_svc->unit);
[8ae8262]142 if (rc != EOK) {
143 sysman_log(LVL_WARN, "Can't remove unit %s (%i).",
144 unit_name(&u_svc->unit), rc);
145 repo_rollback();
146 return;
147 }
148
149 repo_commit();
150}
151
[e8747bd8]152static void sysman_event_task_event(void *data)
153{
154 sm_task_event_t *tev = data;
155
[b55f62a]156 sysman_log(LVL_DEBUG2, "%s, %" PRIu64 " %i",
157 __func__, tev->task_id, tev->flags);
[e8747bd8]158 unit_svc_t *u_svc = sm_task_find_service(tev->task_id);
[8ae8262]159
[e8747bd8]160 if (u_svc == NULL) {
[8ae8262]161 if (tev->flags & TASK_WAIT_EXIT) {
162 /* Non-service task exited, ignore. */
163 goto finish;
164 }
165
166 u_svc = sm_task_create_service(tev->task_id);
167 if (u_svc == NULL) {
168 sysman_log(LVL_WARN,
169 "Unable to create anonymous service for task %" PRIu64 ".",
170 tev->task_id);
171 goto finish;
172 }
173
174 sysman_log(LVL_DEBUG, "Created anonymous service %s.",
175 unit_name(&u_svc->unit));
176
177 /* Inject state so that further processing makes sense */
178 u_svc->unit.state = STATE_STARTING;
[e8747bd8]179 }
180
181 /* Simple incomplete state automaton */
182 unit_t *u = &u_svc->unit;
183 sysman_log(LVL_DEBUG2, "%s, %s(%i)@%" PRIu64 " %i",
184 __func__, unit_name(u), u->state, tev->task_id, tev->flags);
185
186 if (tev->flags & TASK_WAIT_EXIT) {
187 // TODO maybe call unit_fail (would be nice to contain reason)
[ed5367b]188 // or move this whole logic to unit_svc.c
189 if (u->state == STATE_STOPPING) {
190 u->state = STATE_STOPPED;
191 } else {
192 // if it has also retval == 0 then it's not fail
193 u->state = STATE_FAILED;
194 }
[8ae8262]195
[c7b9db03]196 } else if (tev->flags & TASK_WAIT_RETVAL) {
[ed5367b]197 assert(u->state == STATE_STARTING);
[e8747bd8]198 u->state = STATE_STARTED;
199 }
200
201 unit_notify_state(u);
202
[8ae8262]203 if ((tev->flags & TASK_WAIT_EXIT) && u_svc->anonymous) {
204 sysman_log(LVL_DEBUG, "Deleted anonymous service %s.",
205 unit_name(&u_svc->unit));
206 sm_task_delete_service(u_svc);
207 }
[e8747bd8]208finish:
209 free(tev);
210}
211
[241f1985]212errno_t sm_task_start(void)
[e8747bd8]213{
[241f1985]214 return task_register_event_handler(&sm_task_event_handler, true);
[e8747bd8]215}
Note: See TracBrowser for help on using the repository browser.