source: mainline/uspace/srv/taskman/main.c@ 62273d1

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

taskman: Implement simple task exit monitoring

  • Property mode set to 100644
File size: 7.0 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 //TODO explain why we don't explicitly accept connection request
61 /* Spawn a 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 // TODO leak? what happens with referenced sessions
82 free(sess_ref);
83
84 if (rc != EOK) {
85 async_answer_0(iid, rc);
86 return;
87 }
88
89 /* Everything OK. */
90}
91
92static void loader_to_ns(ipc_callid_t iid, ipc_call_t *icall)
93{
94 /* Do no accept connection request, forward it instead. */
95 async_exch_t *exch = async_exchange_begin(session_primary);
96 int rc = async_forward_fast(iid, exch, 0, 0, 0, IPC_FF_NONE);
97 async_exchange_end(exch);
98
99 if (rc != EOK) {
100 async_answer_0(iid, rc);
101 return;
102 }
103}
104
105static void taskman_ctl_wait(ipc_callid_t iid, ipc_call_t *icall)
106{
107 task_id_t id = (task_id_t)
108 MERGE_LOUP32(IPC_GET_ARG1(*icall), IPC_GET_ARG2(*icall));
109 int flags = IPC_GET_ARG3(*icall);
110
111 wait_for_task(id, flags, iid, icall);
112}
113
114static void taskman_ctl_retval(ipc_callid_t iid, ipc_call_t *icall)
115{
116 printf("%s:%i\n", __func__, __LINE__);
117 int rc = task_set_retval(icall);
118 async_answer_0(iid, rc);
119}
120
121static void task_exit_event(ipc_callid_t iid, ipc_call_t *icall, void *arg)
122{
123 printf("%s:%i\n", __func__, __LINE__);
124 // TODO design substitution for taskmon (monitoring)
125 task_id_t id = MERGE_LOUP32(IPC_GET_ARG1(*icall), IPC_GET_ARG2(*icall));
126 task_terminated(id, (task_exit_t)arg);
127}
128
129static void control_connection_loop(void)
130{
131 while (true) {
132 ipc_call_t call;
133 ipc_callid_t callid = async_get_call(&call);
134
135 if (!IPC_GET_IMETHOD(call)) {
136 /* Client disconnected */
137 break;
138 }
139
140 switch (IPC_GET_IMETHOD(call)) {
141 case TASKMAN_WAIT:
142 taskman_ctl_wait(callid, &call);
143 break;
144 case TASKMAN_RETVAL:
145 taskman_ctl_retval(callid, &call);
146 break;
147 default:
148 async_answer_0(callid, ENOENT);
149 }
150 }
151}
152
153static void control_connection(ipc_callid_t iid, ipc_call_t *icall)
154{
155 /* First, accept connection */
156 async_answer_0(iid, EOK);
157
158 // TODO register task to hash table
159 control_connection_loop();
160}
161
162static void loader_callback(ipc_callid_t iid, ipc_call_t *icall)
163{
164 // TODO check that loader is expected, would probably discard prodcons
165 // scheme
166
167 /* Preallocate session container */
168 sess_ref_t *sess_ref = malloc(sizeof(sess_ref_t));
169 if (sess_ref == NULL) {
170 async_answer_0(iid, ENOMEM);
171 }
172
173 /* Create callback connection */
174 sess_ref->sess = async_callback_receive_start(EXCHANGE_ATOMIC, icall);
175 if (sess_ref->sess == NULL) {
176 //TODO different error code?
177 async_answer_0(iid, EINVAL);
178 return;
179 }
180
181 /* Remember task_id */
182 int rc = task_id_intro(icall);
183
184 if (rc != EOK) {
185 async_answer_0(iid, rc);
186 free(sess_ref);
187 return;
188 }
189 async_answer_0(iid, EOK);
190
191 /* Notify spawners */
192 link_initialize(&sess_ref->link);
193 prodcons_produce(&sess_queue, &sess_ref->link);
194}
195
196static void taskman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
197{
198 taskman_interface_t iface = IPC_GET_ARG1(*icall);
199 switch (iface) {
200 case TASKMAN_CONNECT_TO_LOADER:
201 connect_to_loader(iid, icall);
202 break;
203 case TASKMAN_LOADER_TO_NS:
204 loader_to_ns(iid, icall);
205 break;
206 case TASKMAN_CONTROL:
207 control_connection(iid, icall);
208 // ---- interrupt here ----
209 // implement control connection body (setup wait)
210 // ------------------------
211 break;
212 default:
213 /* Unknown interface */
214 async_answer_0(iid, ENOENT);
215 }
216}
217
218static void implicit_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
219{
220 taskman_interface_t iface = IPC_GET_ARG1(*icall);
221 switch (iface) {
222 case TASKMAN_LOADER_CALLBACK:
223 loader_callback(iid, icall);
224 // TODO register task to hashtable
225 control_connection_loop();
226 break;
227 default:
228 /* Unknown interface on implicit connection */
229 async_answer_0(iid, EHANGUP);
230 }
231}
232
233/** Build hard coded configuration */
234
235
236int main(int argc, char *argv[])
237{
238 printf(NAME ": HelenOS task manager\n");
239
240 /* Initialization */
241 prodcons_initialize(&sess_queue);
242 int rc = task_init();
243 if (rc != EOK) {
244 return rc;
245 }
246
247 rc = async_event_subscribe(EVENT_EXIT, task_exit_event, (void *)EVENT_EXIT);
248 if (rc != EOK) {
249 printf("Cannot register for exit events (%i).\n", rc);
250 return rc;
251 }
252
253 rc = async_event_subscribe(EVENT_FAULT, task_exit_event, (void *)EVENT_FAULT);
254 if (rc != EOK) {
255 printf("Cannot register for fault events (%i).\n", rc);
256 return rc;
257 }
258
259 /* We're service too */
260 rc = service_register(SERVICE_TASKMAN);
261 if (rc != EOK) {
262 printf("Cannot register at naming service (%i).\n", rc);
263 return rc;
264 }
265
266 /* Start sysman server */
267 async_set_client_connection(taskman_connection);
268 async_set_implicit_connection(implicit_connection);
269
270 printf(NAME ": Accepting connections\n");
271 //TODO task_retval(EOK);
272 async_manager();
273
274 /* not reached */
275 return 0;
276}
Note: See TracBrowser for help on using the repository browser.