Changeset 2f44fafd in mainline for uspace/srv/taskman/task.c
- Timestamp:
- 2019-08-07T04:33:20Z (6 years ago)
- Children:
- e0e7eba
- Parents:
- 62273d1
- git-author:
- Michal Koutný <xm.koutny+hos@…> (2015-10-12 21:58:23)
- git-committer:
- Matthieu Riolo <matthieu.riolo@…> (2019-08-07 04:33:20)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/taskman/task.c
r62273d1 r2f44fafd 1 1 /* 2 * Copyright (c) 2009 Martin Decky3 * Copyright (c) 2009 Jiri Svoboda4 * Copyright (c) 2015 Michal Koutny5 * All rights reserved.6 * 7 * Redistribution and use in source and binary forms, with or without2 * copyright (c) 2009 martin decky 3 * copyright (c) 2009 jiri svoboda 4 * copyright (c) 2015 michal koutny 5 * all rights reserved. 6 * 7 * redistribution and use in source and binary forms, with or without 8 8 * modification, are permitted provided that the following conditions 9 9 * are met: 10 10 * 11 * - Redistributions of source code must retain the above copyright11 * - redistributions of source code must retain the above copyright 12 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above copyright13 * - redistributions in binary form must reproduce the above copyright 14 14 * notice, this list of conditions and the following disclaimer in the 15 15 * documentation and/or other materials provided with the distribution. 16 * - The name of the author may not be used to endorse or promote products16 * - the name of the author may not be used to endorse or promote products 17 17 * derived from this software without specific prior written permission. 18 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT27 * ( INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.19 * this software is provided by the author ``as is'' and any express or 20 * implied warranties, including, but not limited to, the implied warranties 21 * of merchantability and fitness for a particular purpose are disclaimed. 22 * in no event shall the author be liable for any direct, indirect, 23 * incidental, special, exemplary, or consequential damages (including, but 24 * not limited to, procurement of substitute goods or services; loss of use, 25 * data, or profits; or business interruption) however caused and on any 26 * theory of liability, whether in contract, strict liability, or tort 27 * (including negligence or otherwise) arising in any way out of the use of 28 * this software, even if advised of the possibility of such damage. 29 29 */ 30 30 31 /** @addtogroup taskman 31 /** 32 * locking order: 33 * - task_hash_table_lock, 34 * - pending_wait_lock. 35 * 36 * @addtogroup taskman 32 37 * @{ 33 38 */ … … 37 42 #include <async.h> 38 43 #include <errno.h> 44 #include <fibril_synch.h> 39 45 #include <macros.h> 40 46 #include <malloc.h> 41 47 #include <stdbool.h> 42 48 #include <stdio.h> 49 #include <task.h> 43 50 #include <types/task.h> 44 51 … … 46 53 #include "taskman.h" 47 54 48 49 /** Task hash table item. */ 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. */ 50 63 typedef struct { 51 64 ht_link_t link; 52 65 53 task_id_t id; /**< Task ID. */54 task_exit_t exit; /**< Task is done. */55 bool have_rval; /**< Task returned a value. */56 int retval; /**< The return value. */66 task_id_t id; /**< task id. */ 67 task_exit_t exit; /**< task is done. */ 68 retval_t retval_type; /**< task returned a value. */ 69 int retval; /**< the return value. */ 57 70 } hashed_task_t; 58 71 … … 75 88 } 76 89 77 /** Perform actions after removal of item from the hash table. */90 /** perform actions after removal of item from the hash table. */ 78 91 static void task_remove(ht_link_t *item) 79 92 { … … 81 94 } 82 95 83 /** Operations for task hash table. */96 /** operations for task hash table. */ 84 97 static hash_table_ops_t task_hash_table_ops = { 85 98 .hash = task_hash, … … 92 105 /** Task hash table structure. */ 93 106 static hash_table_t task_hash_table; 94 95 typedef struct { 96 ht_link_t link; 97 sysarg_t in_phone_hash; /**< Incoming phone hash. */ 98 task_id_t id; /**< Task ID. */ 99 } p2i_entry_t; 100 101 /* phone-to-id hash table operations */ 102 103 static size_t p2i_key_hash(void *key) 104 { 105 sysarg_t in_phone_hash = *(sysarg_t*)key; 106 return in_phone_hash; 107 } 108 109 static size_t p2i_hash(const ht_link_t *item) 110 { 111 p2i_entry_t *entry = hash_table_get_inst(item, p2i_entry_t, link); 112 return entry->in_phone_hash; 113 } 114 115 static bool p2i_key_equal(void *key, const ht_link_t *item) 116 { 117 sysarg_t in_phone_hash = *(sysarg_t*)key; 118 p2i_entry_t *entry = hash_table_get_inst(item, p2i_entry_t, link); 119 120 return (in_phone_hash == entry->in_phone_hash); 121 } 122 123 /** Perform actions after removal of item from the hash table. 124 * 125 * @param item Item that was removed from the hash table. 126 * 127 */ 128 static void p2i_remove(ht_link_t *item) 129 { 130 assert(item); 131 free(hash_table_get_inst(item, p2i_entry_t, link)); 132 } 133 134 /** Operations for task hash table. */ 135 static hash_table_ops_t p2i_ops = { 136 .hash = p2i_hash, 137 .key_hash = p2i_key_hash, 138 .key_equal = p2i_key_equal, 139 .equal = NULL, 140 .remove_callback = p2i_remove 141 }; 142 143 /** Map phone hash to task ID */ 144 static hash_table_t phone_to_id; 107 static FIBRIL_RWLOCK_INITIALIZE(task_hash_table_lock); 145 108 146 109 /** Pending task wait structure. */ … … 149 112 task_id_t id; /**< Task ID. */ 150 113 ipc_callid_t callid; /**< Call ID waiting for the connection */ 151 int flags; /**< Wait flags TODO*/114 int flags; /**< Wait flags */ 152 115 } pending_wait_t; 153 116 154 117 static list_t pending_wait; 118 static FIBRIL_RWLOCK_INITIALIZE(pending_wait_lock); 155 119 156 120 int task_init(void) … … 161 125 } 162 126 163 if (!hash_table_create(&phone_to_id, 0, 0, &p2i_ops)) {164 printf(NAME ": No memory available for tasks\n");165 return ENOMEM;166 }167 168 127 list_initialize(&pending_wait); 169 128 return EOK; 170 129 } 171 130 172 /** Process pending wait requests */ 131 /** Process pending wait requests 132 * 133 * Assumes task_hash_table_lock is hold (at least read) 134 */ 173 135 void process_pending_wait(void) 174 136 { 175 task_exit_t texit; 176 137 fibril_rwlock_write_lock(&pending_wait_lock); 177 138 loop: 178 // W lock179 139 list_foreach(pending_wait, link, pending_wait_t, pr) { 180 // R lock task_hash_table181 140 ht_link_t *link = hash_table_find(&task_hash_table, &pr->id); 182 // R unlock task_hash_table183 141 if (!link) 184 142 continue; 185 143 186 144 hashed_task_t *ht = hash_table_get_inst(link, hashed_task_t, link); 187 if (ht->exit == TASK_EXIT_RUNNING) 188 continue; 189 190 if (!(pr->callid & IPC_CALLID_NOTIFICATION)) { 191 texit = ht->exit; 192 async_answer_2(pr->callid, EOK, texit, 193 ht->retval); 145 int notify_flags = 0; 146 if (ht->exit != TASK_EXIT_RUNNING) { 147 notify_flags |= TASK_WAIT_EXIT; 148 if (ht->retval_type == RVAL_SET_EXIT) { 149 notify_flags |= TASK_WAIT_RETVAL; 150 } 194 151 } 152 if (ht->retval_type == RVAL_SET) { 153 notify_flags |= TASK_WAIT_RETVAL; 154 } 155 156 int match = notify_flags & pr->flags; 157 bool answer = !(pr->callid & IPC_CALLID_NOTIFICATION); 158 159 if (match == 0) { 160 if (notify_flags & TASK_WAIT_EXIT) { 161 /* Nothing to wait for anymore */ 162 if (answer) { 163 async_answer_0(pr->callid, EINVAL); 164 } 165 } else { 166 /* Maybe later */ 167 continue; 168 } 169 } else if (answer) { 170 /* Send both exit status and retval, caller should know 171 * what is valid */ 172 async_answer_2(pr->callid, EOK, ht->exit, ht->retval); 173 } 174 195 175 196 176 list_remove(&pr->link); … … 198 178 goto loop; 199 179 } 200 // W unlock180 fibril_rwlock_write_unlock(&pending_wait_lock); 201 181 } 202 182 203 183 void wait_for_task(task_id_t id, int flags, ipc_callid_t callid, ipc_call_t *call) 204 184 { 205 // R lock185 fibril_rwlock_read_lock(&task_hash_table_lock); 206 186 ht_link_t *link = hash_table_find(&task_hash_table, &id); 207 // R unlock 187 fibril_rwlock_read_unlock(&task_hash_table_lock); 188 208 189 hashed_task_t *ht = (link != NULL) ? 209 190 hash_table_get_inst(link, hashed_task_t, link) : NULL; … … 235 216 pr->flags = flags; 236 217 pr->callid = callid; 237 // W lock 218 219 fibril_rwlock_write_lock(&pending_wait_lock); 238 220 list_append(&pr->link, &pending_wait); 239 // W unlock 240 } 241 242 int task_id_intro(ipc_call_t *call) 243 { 244 // TODO think about task_id reuse and this 245 // R lock 221 fibril_rwlock_write_unlock(&pending_wait_lock); 222 } 223 224 int task_intro(ipc_call_t *call, bool check_unique) 225 { 226 int rc = EOK; 227 228 fibril_rwlock_write_lock(&task_hash_table_lock); 229 246 230 ht_link_t *link = hash_table_find(&task_hash_table, &call->in_task_id); 247 // R unlock 248 if (link != NULL) 249 return EEXISTS; 231 if (link != NULL) { 232 rc = EEXISTS; 233 goto finish; 234 } 250 235 251 236 hashed_task_t *ht = (hashed_task_t *) malloc(sizeof(hashed_task_t)); 252 if (ht == NULL) 253 return ENOMEM; 237 if (ht == NULL) { 238 rc = ENOMEM; 239 goto finish; 240 } 254 241 255 242 /* … … 258 245 ht->id = call->in_task_id; 259 246 ht->exit = TASK_EXIT_RUNNING; 260 ht-> have_rval = false;247 ht->retval_type = RVAL_UNSET; 261 248 ht->retval = -1; 262 // W lock 249 263 250 hash_table_insert(&task_hash_table, &ht->link); 264 // W unlock 265 266 return EOK; 251 252 finish: 253 fibril_rwlock_write_unlock(&task_hash_table_lock); 254 return rc; 267 255 } 268 256 269 257 int task_set_retval(ipc_call_t *call) 270 258 { 259 int rc = EOK; 271 260 task_id_t id = call->in_task_id; 272 261 273 // R lock262 fibril_rwlock_read_lock(&task_hash_table_lock); 274 263 ht_link_t *link = hash_table_find(&task_hash_table, &id); 275 // R unlock 264 276 265 hashed_task_t *ht = (link != NULL) ? 277 266 hash_table_get_inst(link, hashed_task_t, link) : NULL; 278 267 279 if ((ht == NULL) || (ht->exit != TASK_EXIT_RUNNING)) 280 r eturnEINVAL;281 282 // TODO process additional flag to retval283 ht->have_rval = true;268 if ((ht == NULL) || (ht->exit != TASK_EXIT_RUNNING)) { 269 rc = EINVAL; 270 goto finish; 271 } 272 284 273 ht->retval = IPC_GET_ARG1(*call); 274 ht->retval_type = IPC_GET_ARG2(*call) ? RVAL_SET_EXIT : RVAL_SET; 285 275 286 276 process_pending_wait(); 287 277 288 return EOK; 278 finish: 279 fibril_rwlock_read_unlock(&task_hash_table_lock); 280 return rc; 289 281 } 290 282 … … 292 284 { 293 285 /* Mark task as finished. */ 294 // R lock286 fibril_rwlock_write_lock(&task_hash_table_lock); 295 287 ht_link_t *link = hash_table_find(&task_hash_table, &id); 296 // R unlock297 if (link == NULL)298 return;288 if (link == NULL) { 289 goto finish; 290 } 299 291 300 292 hashed_task_t *ht = hash_table_get_inst(link, hashed_task_t, link); 301 293 302 ht->exit = texit; 294 if (ht->retval_type == RVAL_UNSET) { 295 ht->exit = TASK_EXIT_UNEXPECTED; 296 } else { 297 ht->exit = texit; 298 } 303 299 process_pending_wait(); 304 300 305 // W lock306 301 hash_table_remove_item(&task_hash_table, &ht->link); 307 // W unlock 302 finish: 303 fibril_rwlock_write_unlock(&task_hash_table_lock); 308 304 } 309 305
Note:
See TracChangeset
for help on using the changeset viewer.