Changeset 035d7d8 in mainline
- Timestamp:
- 2019-08-07T05:49:44Z (5 years ago)
- Children:
- 2aaccd3
- Parents:
- 456f7ae
- git-author:
- Michal Koutný <xm.koutny+hos@…> (2015-10-21 22:44:26)
- git-committer:
- Matthieu Riolo <matthieu.riolo@…> (2019-08-07 05:49:44)
- Location:
- uspace
- Files:
-
- 2 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/tester/proc/task_anywait.c
r456f7ae r035d7d8 60 60 61 61 handler_hit = true; 62 if (flags & TASK_WAIT_EXIT) { 63 last_texit = texit; 64 } 65 66 last_has_retval = flags & TASK_WAIT_RETVAL; 67 if (last_has_retval) { 68 last_retval = retval; 69 } 70 62 71 finish: 63 72 fibril_condvar_signal(&sync_cv); -
uspace/srv/net/tcp/service.c
r456f7ae r035d7d8 35 35 */ 36 36 37 #include <async.h>38 37 #include <errno.h> 39 38 #include <str_error.h> -
uspace/srv/taskman/Makefile
r456f7ae r035d7d8 32 32 33 33 SOURCES = \ 34 event.c \ 34 35 main.c \ 35 36 task.c -
uspace/srv/taskman/main.c
r456f7ae r035d7d8 39 39 #include <stdlib.h> 40 40 41 #include "event.h" 41 42 #include "task.h" 42 43 #include "taskman.h" … … 63 64 64 65 if (rc != EOK) { 66 printf(NAME ": %s -> %i\n", __func__, rc); 65 67 async_answer_0(iid, rc); 66 68 return; … … 125 127 { 126 128 printf("%s:%i from %llu\n", __func__, __LINE__, icall->in_task_id); 127 async_answer_0(iid, ENOTSUP); // TODO interrupt here 129 /* Atomic -- will be used for notifications only */ 130 async_sess_t *sess = async_callback_receive(EXCHANGE_ATOMIC); 131 if (sess == NULL) { 132 async_answer_0(iid, ENOMEM); 133 return; 134 } 135 136 int rc = event_register_listener(icall->in_task_id, sess); 137 async_answer_0(iid, rc); 128 138 } 129 139 … … 268 278 return rc; 269 279 } 280 rc = event_init(); 281 if (rc != EOK) { 282 return rc; 283 } 270 284 271 285 rc = async_event_subscribe(EVENT_EXIT, task_exit_event, NULL); -
uspace/srv/taskman/task.c
r456f7ae r035d7d8 30 30 31 31 /** 32 * locking order: 32 * locking order: (TODO move to main?) 33 33 * - task_hash_table_lock, 34 34 * - pending_wait_lock. 35 * - listeners_lock 35 36 * 36 37 * @addtogroup taskman … … 38 39 */ 39 40 40 #include <adt/hash_table.h>41 41 #include <assert.h> 42 42 #include <async.h> 43 43 #include <errno.h> 44 #include <fibril_synch.h>45 44 #include <macros.h> 46 45 #include <malloc.h> … … 53 52 #include "taskman.h" 54 53 55 /** what type of retval from the task we have */56 typedef enum {57 RVAL_UNSET, /**< unset */58 RVAL_SET, /**< retval set, e.g. by server */59 RVAL_SET_EXIT /**< retval set, wait for expected task exit */60 } retval_t;61 62 /** Task hash table item. */63 typedef struct {64 ht_link_t link;65 66 task_id_t id; /**< Task id. */67 task_exit_t exit; /**< Task's uspace exit status. */68 bool failed; /**< Task failed. */69 retval_t retval_type; /**< Task returned a value. */70 int retval; /**< The return value. */71 } hashed_task_t;72 73 74 54 static size_t task_key_hash(void *key) 75 55 { … … 79 59 static size_t task_hash(const ht_link_t *item) 80 60 { 81 hashed_task_t *ht = hash_table_get_inst(item, hashed_task_t, link);61 task_t *ht = hash_table_get_inst(item, task_t, link); 82 62 return ht->id; 83 63 } … … 85 65 static bool task_key_equal(void *key, const ht_link_t *item) 86 66 { 87 hashed_task_t *ht = hash_table_get_inst(item, hashed_task_t, link);67 task_t *ht = hash_table_get_inst(item, task_t, link); 88 68 return ht->id == *(task_id_t*)key; 89 69 } … … 92 72 static void task_remove(ht_link_t *item) 93 73 { 94 free(hash_table_get_inst(item, hashed_task_t, link));74 free(hash_table_get_inst(item, task_t, link)); 95 75 } 96 76 … … 105 85 106 86 /** Task hash table structure. */ 107 static hash_table_t task_hash_table; 108 static FIBRIL_RWLOCK_INITIALIZE(task_hash_table_lock); 109 110 /** Pending task wait structure. */ 111 typedef struct { 112 link_t link; 113 task_id_t id; /**< Task ID who we wait for. */ 114 task_id_t waiter_id; /**< Task ID who waits. */ 115 ipc_callid_t callid; /**< Call ID waiting for the connection */ 116 int flags; /**< Wait flags */ 117 } pending_wait_t; 118 119 static list_t pending_wait; 120 static FIBRIL_RWLOCK_INITIALIZE(pending_wait_lock); 87 hash_table_t task_hash_table; 88 fibril_rwlock_t task_hash_table_lock; 121 89 122 90 int task_init(void) … … 126 94 return ENOMEM; 127 95 } 96 97 fibril_rwlock_initialize(&task_hash_table_lock); 128 98 129 list_initialize(&pending_wait);130 99 return EOK; 131 100 } 132 101 133 /** Process pending wait requests102 /** Find task by its ID 134 103 * 135 * Assumes task_hash_table_lock is hold (at least read) 104 * Assumes held lock of task_hash_table. 105 * 106 * @param[in] id 107 * @return task structure 108 * @return NULL when no task with given ID exists 136 109 */ 137 void process_pending_wait(void)110 task_t *task_get_by_id(task_id_t id) 138 111 { 139 fibril_rwlock_write_lock(&pending_wait_lock);140 loop:141 list_foreach(pending_wait, link, pending_wait_t, pr) {142 ht_link_t *link = hash_table_find(&task_hash_table, &pr->id);143 if (!link)144 continue;145 146 hashed_task_t *ht = hash_table_get_inst(link, hashed_task_t, link);147 int notify_flags = 0;148 if (ht->exit != TASK_EXIT_RUNNING) {149 notify_flags |= TASK_WAIT_EXIT;150 if (ht->retval_type == RVAL_SET_EXIT) {151 notify_flags |= TASK_WAIT_RETVAL;152 }153 }154 if (ht->retval_type == RVAL_SET) {155 notify_flags |= TASK_WAIT_RETVAL;156 }157 158 /*159 * In current implementation you can wait for single retval,160 * thus it can be never present in rest flags.161 */162 int rest = (~notify_flags & pr->flags) & ~TASK_WAIT_RETVAL;163 rest &= ~TASK_WAIT_BOTH;164 int match = notify_flags & pr->flags;165 bool answer = !(pr->callid & IPC_CALLID_NOTIFICATION);166 printf("%s: %x; %x, %x\n", __func__, pr->flags, rest, match);167 168 if (match == 0) {169 if (notify_flags & TASK_WAIT_EXIT) {170 /* Nothing to wait for anymore */171 if (answer) {172 async_answer_0(pr->callid, EINVAL);173 }174 } else {175 /* Maybe later */176 continue;177 }178 } else if (answer) {179 if ((pr->flags & TASK_WAIT_BOTH) && match == TASK_WAIT_EXIT) {180 async_answer_1(pr->callid, EINVAL, ht->exit);181 } else {182 /* Send both exit status and retval, caller183 * should know what is valid */184 async_answer_3(pr->callid, EOK, ht->exit,185 ht->retval, rest);186 }187 188 /* Pending wait has one more chance */189 if (rest && (pr->flags & TASK_WAIT_BOTH)) {190 pr->flags = rest | TASK_WAIT_BOTH;191 continue;192 }193 }194 195 196 list_remove(&pr->link);197 free(pr);198 goto loop;199 }200 fibril_rwlock_write_unlock(&pending_wait_lock);201 }202 203 void wait_for_task(task_id_t id, int flags, ipc_callid_t callid, ipc_call_t *call)204 {205 assert(!(flags & TASK_WAIT_BOTH) ||206 ((flags & TASK_WAIT_RETVAL) && (flags & TASK_WAIT_EXIT)));207 208 fibril_rwlock_read_lock(&task_hash_table_lock);209 112 ht_link_t *link = hash_table_find(&task_hash_table, &id); 210 fibril_rwlock_read_unlock(&task_hash_table_lock); 211 212 hashed_task_t *ht = (link != NULL) ? 213 hash_table_get_inst(link, hashed_task_t, link) : NULL; 214 215 if (ht == NULL) { 216 /* No such task exists. */ 217 async_answer_0(callid, ENOENT); 218 return; 113 if (!link) { 114 return NULL; 219 115 } 220 116 221 if (ht->exit != TASK_EXIT_RUNNING) { 222 //TODO are flags BOTH processed correctly here? 223 async_answer_3(callid, EOK, ht->exit, ht->retval, 0); 224 return; 225 } 226 227 /* 228 * Add request to pending list or reuse existing item for a second 229 * wait. 230 */ 231 task_id_t waiter_id = call->in_task_id; 232 fibril_rwlock_write_lock(&pending_wait_lock); 233 pending_wait_t *pr = NULL; 234 list_foreach(pending_wait, link, pending_wait_t, it) { 235 if (it->id == id && it->waiter_id == waiter_id) { 236 pr = it; 237 break; 238 } 239 } 240 241 int rc = EOK; 242 bool reuse = false; 243 if (pr == NULL) { 244 pr = malloc(sizeof(pending_wait_t)); 245 if (!pr) { 246 rc = ENOMEM; 247 goto finish; 248 } 249 250 link_initialize(&pr->link); 251 pr->id = id; 252 pr->waiter_id = waiter_id; 253 pr->flags = flags; 254 pr->callid = callid; 255 256 list_append(&pr->link, &pending_wait); 257 rc = EOK; 258 } else if (!(pr->flags & TASK_WAIT_BOTH)) { 259 /* 260 * One task can wait for another task only once (per task, not 261 * fibril). 262 */ 263 rc = EEXISTS; 264 } else { 265 /* 266 * Reuse pending wait for the second time. 267 */ 268 pr->flags &= ~TASK_WAIT_BOTH; // TODO maybe new flags should be set? 269 pr->callid = callid; 270 reuse = true; 271 } 272 printf("%s: %llu: %x, %x, %i\n", __func__, pr->id, flags, pr->flags, reuse); 273 274 finish: 275 fibril_rwlock_write_unlock(&pending_wait_lock); 276 // TODO why IPC_CALLID_NOTIFICATION? explain! 277 if (rc != EOK && !(callid & IPC_CALLID_NOTIFICATION)) 278 async_answer_0(callid, rc); 279 117 task_t *t = hash_table_get_inst(link, task_t, link); 118 return t; 280 119 } 281 120 … … 286 125 fibril_rwlock_write_lock(&task_hash_table_lock); 287 126 288 ht_link_t *link = hash_table_find(&task_hash_table, &call->in_task_id);289 if ( link!= NULL) {127 task_t *t = task_get_by_id(call->in_task_id); 128 if (t != NULL) { 290 129 rc = EEXISTS; 291 130 goto finish; 292 131 } 293 132 294 hashed_task_t *ht = (hashed_task_t *) malloc(sizeof(hashed_task_t));295 if ( ht == NULL) {133 t = malloc(sizeof(task_t)); 134 if (t == NULL) { 296 135 rc = ENOMEM; 297 136 goto finish; … … 301 140 * Insert into the main table. 302 141 */ 303 ht->id = call->in_task_id; 304 ht->exit = TASK_EXIT_RUNNING; 305 ht->failed = false; 306 ht->retval_type = RVAL_UNSET; 307 ht->retval = -1; 142 t->id = call->in_task_id; 143 t->exit = TASK_EXIT_RUNNING; 144 t->failed = false; 145 t->retval_type = RVAL_UNSET; 146 t->retval = -1; 147 link_initialize(&t->listeners); 148 t->sess = NULL; 308 149 309 hash_table_insert(&task_hash_table, & ht->link);310 printf("%s: %llu\n", __func__, ht->id);150 hash_table_insert(&task_hash_table, &t->link); 151 printf("%s: %llu\n", __func__, t->id); 311 152 312 153 finish: … … 315 156 } 316 157 317 int task_set_retval(ipc_call_t *call)318 {319 int rc = EOK;320 task_id_t id = call->in_task_id;321 322 fibril_rwlock_write_lock(&task_hash_table_lock);323 ht_link_t *link = hash_table_find(&task_hash_table, &id);324 325 hashed_task_t *ht = (link != NULL) ?326 hash_table_get_inst(link, hashed_task_t, link) : NULL;327 328 if ((ht == NULL) || (ht->exit != TASK_EXIT_RUNNING)) {329 rc = EINVAL;330 goto finish;331 }332 333 ht->retval = IPC_GET_ARG1(*call);334 ht->retval_type = IPC_GET_ARG2(*call) ? RVAL_SET_EXIT : RVAL_SET;335 336 process_pending_wait();337 338 finish:339 fibril_rwlock_write_unlock(&task_hash_table_lock);340 return rc;341 }342 343 void task_terminated(task_id_t id, exit_reason_t exit_reason)344 {345 /* Mark task as finished. */346 fibril_rwlock_write_lock(&task_hash_table_lock);347 ht_link_t *link = hash_table_find(&task_hash_table, &id);348 if (link == NULL) {349 goto finish;350 }351 352 hashed_task_t *ht = hash_table_get_inst(link, hashed_task_t, link);353 354 /*355 * If daemon returns a value and then fails/is killed, it's an356 * unexpected termination.357 */358 if (ht->retval_type == RVAL_UNSET || exit_reason == EXIT_REASON_KILLED) {359 ht->exit = TASK_EXIT_UNEXPECTED;360 } else if (ht->failed) {361 ht->exit = TASK_EXIT_UNEXPECTED;362 } else {363 ht->exit = TASK_EXIT_NORMAL;364 }365 process_pending_wait();366 367 hash_table_remove_item(&task_hash_table, &ht->link);368 finish:369 fibril_rwlock_write_unlock(&task_hash_table_lock);370 }371 372 void task_failed(task_id_t id)373 {374 /* Mark task as failed. */375 fibril_rwlock_write_lock(&task_hash_table_lock);376 ht_link_t *link = hash_table_find(&task_hash_table, &id);377 if (link == NULL) {378 goto finish;379 }380 381 hashed_task_t *ht = hash_table_get_inst(link, hashed_task_t, link);382 383 ht->failed = true;384 // TODO design substitution for taskmon (monitoring) = invoke dump utility385 386 finish:387 fibril_rwlock_write_unlock(&task_hash_table_lock);388 }389 158 390 159 /** -
uspace/srv/taskman/task.h
r456f7ae r035d7d8 35 35 #define TASKMAN_TASK_H__ 36 36 37 #include <abi/proc/task.h> 38 #include <adt/hash_table.h> 39 #include <adt/list.h> 40 #include <fibril_synch.h> 37 41 #include <ipc/common.h> 38 #include <abi/proc/task.h> 42 43 /** What type of retval from the task we have */ 44 typedef enum { 45 RVAL_UNSET, /**< unset */ 46 RVAL_SET, /**< retval set, e.g. by server */ 47 RVAL_SET_EXIT /**< retval set, wait for expected task exit */ 48 } retval_t; 49 50 /** Holds necessary information of each (registered) task. */ 51 typedef struct { 52 ht_link_t link; 53 54 task_id_t id; /**< Task id. */ 55 task_exit_t exit; /**< Task's uspace exit status. */ 56 bool failed; /**< Task failed (task can exit unexpectedly 57 even w/out failure). */ 58 retval_t retval_type; /**< Task returned a value. */ 59 int retval; /**< The return value. */ 60 61 link_t listeners; /**< Link to listeners list. */ 62 async_sess_t *sess; /**< Session for notifications to task. */ 63 } task_t; 64 65 extern hash_table_t task_hash_table; 66 extern fibril_rwlock_t task_hash_table_lock; 39 67 40 68 extern int task_init(void); 41 extern void process_pending_wait(void);42 69 43 extern void wait_for_task(task_id_t, int, ipc_callid_t, ipc_call_t *); 44 extern int task_set_retval(ipc_call_t *); 70 extern task_t *task_get_by_id(task_id_t); 45 71 46 72 extern int task_intro(ipc_call_t *, bool); 47 extern void task_terminated(task_id_t, exit_reason_t);48 extern void task_failed(task_id_t);49 73 50 74 #endif
Note:
See TracChangeset
for help on using the changeset viewer.