source: mainline/uspace/srv/taskman/main.c@ d4ec49e

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

taskman: Implement waiting both for retval and exit
Conflicts:

uspace/lib/c/generic/task.c
uspace/lib/c/include/task.h

  • Property mode set to 100644
File size: 7.3 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/prodcons.h>
30#include <assert.h>
31#include <async.h>
32#include <errno.h>
33#include <ipc/services.h>
34#include <ipc/taskman.h>
35#include <loader/loader.h>
36#include <macros.h>
37#include <ns.h>
38#include <stdio.h>
39#include <stdlib.h>
40
41#include "task.h"
42#include "taskman.h"
43
44//TODO move to appropriate header file
45extern async_sess_t *session_primary;
46
47typedef struct {
48 link_t link;
49 async_sess_t *sess;
50} sess_ref_t;
51
52static prodcons_t sess_queue;
53
54
55/*
56 * Static functions
57 */
58static void connect_to_loader(ipc_callid_t iid, ipc_call_t *icall)
59{
60 /* We don't accept the connection request, we forward it instead to
61 * freshly spawned loader. */
62 int rc = loader_spawn("loader");
63
64 if (rc != EOK) {
65 async_answer_0(iid, rc);
66 return;
67 }
68
69 /* Wait until spawned task presents itself to us. */
70 link_t *link = prodcons_consume(&sess_queue);
71 sess_ref_t *sess_ref = list_get_instance(link, sess_ref_t, link);
72
73 /* Forward the connection request (strip interface arg). */
74 async_exch_t *exch = async_exchange_begin(sess_ref->sess);
75 rc = async_forward_fast(iid, exch,
76 IPC_GET_ARG2(*icall),
77 IPC_GET_ARG3(*icall),
78 0, IPC_FF_NONE);
79 async_exchange_end(exch);
80
81 /* After forward we can dispose all session-related resources */
82 async_hangup(sess_ref->sess);
83 free(sess_ref);
84
85 if (rc != EOK) {
86 async_answer_0(iid, rc);
87 return;
88 }
89
90 /* Everything OK. */
91}
92
93static void loader_to_ns(ipc_callid_t iid, ipc_call_t *icall)
94{
95 /* Do no accept connection request, forward it instead. */
96 async_exch_t *exch = async_exchange_begin(session_primary);
97 int rc = async_forward_fast(iid, exch, 0, 0, 0, IPC_FF_NONE);
98 async_exchange_end(exch);
99
100 if (rc != EOK) {
101 async_answer_0(iid, rc);
102 return;
103 }
104}
105
106static void taskman_ctl_wait(ipc_callid_t iid, ipc_call_t *icall)
107{
108 task_id_t id = (task_id_t)
109 MERGE_LOUP32(IPC_GET_ARG1(*icall), IPC_GET_ARG2(*icall));
110 int flags = IPC_GET_ARG3(*icall);
111
112 wait_for_task(id, flags, iid, icall);
113}
114
115static void taskman_ctl_retval(ipc_callid_t iid, ipc_call_t *icall)
116{
117 printf("%s:%i from %llu\n", __func__, __LINE__, icall->in_task_id);
118 int rc = task_set_retval(icall);
119 async_answer_0(iid, rc);
120}
121
122static void task_exit_event(ipc_callid_t iid, ipc_call_t *icall, void *arg)
123{
124 // TODO design substitution for taskmon (monitoring)
125 task_id_t id = MERGE_LOUP32(IPC_GET_ARG1(*icall), IPC_GET_ARG2(*icall));
126 printf("%s:%i from %llu/%i\n", __func__, __LINE__, id, (task_exit_t)arg);
127 task_terminated(id, (task_exit_t)arg);
128}
129
130static void control_connection_loop(void)
131{
132 while (true) {
133 ipc_call_t call;
134 ipc_callid_t callid = async_get_call(&call);
135
136 if (!IPC_GET_IMETHOD(call)) {
137 /* Client disconnected */
138 break;
139 }
140
141 switch (IPC_GET_IMETHOD(call)) {
142 case TASKMAN_WAIT:
143 taskman_ctl_wait(callid, &call);
144 break;
145 case TASKMAN_RETVAL:
146 taskman_ctl_retval(callid, &call);
147 break;
148 default:
149 async_answer_0(callid, ENOENT);
150 }
151 }
152}
153
154static void control_connection(ipc_callid_t iid, ipc_call_t *icall)
155{
156 /* TODO remove/redesign the workaround
157 * Call task_intro here for boot-time tasks,
158 * probably they should announce themselves explicitly
159 * or taskman should detect them from kernel's list of tasks.
160 */
161 int rc = task_intro(icall, false);
162
163 /* First, accept connection */
164 async_answer_0(iid, rc);
165
166 if (rc != EOK) {
167 return;
168 }
169
170 control_connection_loop();
171}
172
173static void loader_callback(ipc_callid_t iid, ipc_call_t *icall)
174{
175 // TODO check that loader is expected, would probably discard prodcons
176 // scheme
177
178 /* Preallocate session container */
179 sess_ref_t *sess_ref = malloc(sizeof(sess_ref_t));
180 if (sess_ref == NULL) {
181 async_answer_0(iid, ENOMEM);
182 }
183
184 /* Create callback connection */
185 sess_ref->sess = async_callback_receive_start(EXCHANGE_ATOMIC, icall);
186 if (sess_ref->sess == NULL) {
187 async_answer_0(iid, EINVAL);
188 return;
189 }
190
191 /* Remember task_id */
192 int rc = task_intro(icall, true);
193
194 if (rc != EOK) {
195 async_answer_0(iid, rc);
196 free(sess_ref);
197 return;
198 }
199 async_answer_0(iid, EOK);
200
201 /* Notify spawners */
202 link_initialize(&sess_ref->link);
203 prodcons_produce(&sess_queue, &sess_ref->link);
204}
205
206static void taskman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
207{
208 taskman_interface_t iface = IPC_GET_ARG1(*icall);
209 switch (iface) {
210 case TASKMAN_CONNECT_TO_LOADER:
211 connect_to_loader(iid, icall);
212 break;
213 case TASKMAN_LOADER_TO_NS:
214 loader_to_ns(iid, icall);
215 break;
216 case TASKMAN_CONTROL:
217 control_connection(iid, icall);
218 // ---- interrupt here ----
219 // implement control connection body (setup wait)
220 // ------------------------
221 break;
222 default:
223 /* Unknown interface */
224 async_answer_0(iid, ENOENT);
225 }
226}
227
228static void implicit_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
229{
230 taskman_interface_t iface = IPC_GET_ARG1(*icall);
231 switch (iface) {
232 case TASKMAN_LOADER_CALLBACK:
233 loader_callback(iid, icall);
234 control_connection_loop();
235 break;
236 default:
237 /* Unknown interface on implicit connection */
238 async_answer_0(iid, EHANGUP);
239 }
240}
241
242/** Build hard coded configuration */
243
244
245int main(int argc, char *argv[])
246{
247 printf(NAME ": HelenOS task manager\n");
248
249 /* Initialization */
250 prodcons_initialize(&sess_queue);
251 int rc = task_init();
252 if (rc != EOK) {
253 return rc;
254 }
255
256 rc = async_event_subscribe(EVENT_EXIT, task_exit_event, (void *)TASK_EXIT_NORMAL);
257 if (rc != EOK) {
258 printf("Cannot register for exit events (%i).\n", rc);
259 return rc;
260 }
261
262 rc = async_event_subscribe(EVENT_FAULT, task_exit_event, (void *)TASK_EXIT_UNEXPECTED);
263 if (rc != EOK) {
264 printf("Cannot register for fault events (%i).\n", rc);
265 return rc;
266 }
267
268 /* We're service too */
269 rc = service_register(SERVICE_TASKMAN);
270 if (rc != EOK) {
271 printf("Cannot register at naming service (%i).\n", rc);
272 return rc;
273 }
274
275 /* Start sysman server */
276 async_set_client_connection(taskman_connection);
277 async_set_implicit_connection(implicit_connection);
278
279 printf(NAME ": Accepting connections\n");
280 //TODO task_retval(EOK);
281 async_manager();
282
283 /* not reached */
284 return 0;
285}
Note: See TracBrowser for help on using the repository browser.