source: mainline/uspace/srv/sysman/sm_task.c@ 015b147

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

sysman: Refactored unit repo iteration and locking

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