Changes in uspace/lib/c/generic/ipc.c [cde999a:706b4de] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/ipc.c
rcde999a r706b4de 1 1 /* 2 2 * Copyright (c) 2006 Ondrej Palkovsky 3 * Copyright (c) 2017 Jakub Jermar4 3 * All rights reserved. 5 4 * … … 43 42 #include <ipc/ipc.h> 44 43 #include <libc.h> 45 #include < stdlib.h>44 #include <malloc.h> 46 45 #include <errno.h> 47 46 #include <adt/list.h> … … 51 50 52 51 /** 53 * Structures of this type are used for keeping track of sent asynchronous calls. 54 */ 55 typedef struct async_call { 52 * Structures of this type are used for keeping track 53 * of sent asynchronous calls and queing unsent calls. 54 */ 55 typedef struct { 56 link_t list; 57 56 58 ipc_async_callback_t callback; 57 59 void *private; 58 60 59 struct { 60 ipc_call_t data; 61 } msg; 61 union { 62 ipc_callid_t callid; 63 struct { 64 ipc_call_t data; 65 int phoneid; 66 } msg; 67 } u; 68 69 /** Fibril waiting for sending this call. */ 70 fid_t fid; 62 71 } async_call_t; 72 73 LIST_INITIALIZE(dispatched_calls); 74 75 /** List of asynchronous calls that were not accepted by kernel. 76 * 77 * Protected by async_futex, because if the call is not accepted 78 * by the kernel, the async framework is used automatically. 79 * 80 */ 81 LIST_INITIALIZE(queued_calls); 82 83 static futex_t ipc_futex = FUTEX_INITIALIZER; 84 85 /** Send asynchronous message via syscall. 86 * 87 * @param phoneid Phone handle for the call. 88 * @param data Call data with the request. 89 * 90 * @return Hash of the call or an error code. 91 * 92 */ 93 static ipc_callid_t ipc_call_async_internal(int phoneid, ipc_call_t *data) 94 { 95 return __SYSCALL2(SYS_IPC_CALL_ASYNC_SLOW, phoneid, (sysarg_t) data); 96 } 63 97 64 98 /** Prologue for ipc_call_async_*() functions. … … 90 124 /** Epilogue for ipc_call_async_*() functions. 91 125 * 92 * @param rc Value returned by the SYS_IPC_CALL_ASYNC_* syscall. 93 * @param call Structure returned by ipc_prepare_async(). 94 */ 95 static inline void ipc_finish_async(int rc, async_call_t *call) 126 * @param callid Value returned by the SYS_IPC_CALL_ASYNC_* syscall. 127 * @param phoneid Phone handle through which the call was made. 128 * @param call Structure returned by ipc_prepare_async(). 129 */ 130 static inline void ipc_finish_async(ipc_callid_t callid, int phoneid, 131 async_call_t *call) 96 132 { 97 133 if (!call) { 98 134 /* Nothing to do regardless if failed or not */ 135 futex_unlock(&ipc_futex); 99 136 return; 100 137 } 101 138 102 if (rc != EOK) { 139 if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) { 140 futex_unlock(&ipc_futex); 141 103 142 /* Call asynchronous handler with error code */ 104 143 if (call->callback) … … 108 147 return; 109 148 } 149 150 call->u.callid = callid; 151 152 /* Add call to the list of dispatched calls */ 153 list_append(&call->list, &dispatched_calls); 154 futex_unlock(&ipc_futex); 110 155 } 111 156 112 157 /** Fast asynchronous call. 113 158 * 114 * This function can only handle threearguments of payload. It is, however,159 * This function can only handle four arguments of payload. It is, however, 115 160 * faster than the more generic ipc_call_async_slow(). 116 161 * … … 121 166 * error code. If the call cannot be temporarily made, it is queued. 122 167 * 123 * @param phandle Phone handle for the call. 124 * @param imethod Requested interface and method. 125 * @param arg1 Service-defined payload argument. 126 * @param arg2 Service-defined payload argument. 127 * @param arg3 Service-defined payload argument. 128 * @param private Argument to be passed to the answer/error callback. 129 * @param callback Answer or error callback. 130 */ 131 void ipc_call_async_fast(cap_handle_t phandle, sysarg_t imethod, sysarg_t arg1, 132 sysarg_t arg2, sysarg_t arg3, void *private, ipc_async_callback_t callback) 168 * @param phoneid Phone handle for the call. 169 * @param imethod Requested interface and method. 170 * @param arg1 Service-defined payload argument. 171 * @param arg2 Service-defined payload argument. 172 * @param arg3 Service-defined payload argument. 173 * @param arg4 Service-defined payload argument. 174 * @param private Argument to be passed to the answer/error callback. 175 * @param callback Answer or error callback. 176 */ 177 void ipc_call_async_fast(int phoneid, sysarg_t imethod, sysarg_t arg1, 178 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, void *private, 179 ipc_async_callback_t callback) 180 { 181 async_call_t *call = NULL; 182 183 if (callback) { 184 call = ipc_prepare_async(private, callback); 185 if (!call) 186 return; 187 } 188 189 /* 190 * We need to make sure that we get callid 191 * before another thread accesses the queue again. 192 */ 193 194 futex_lock(&ipc_futex); 195 ipc_callid_t callid = __SYSCALL6(SYS_IPC_CALL_ASYNC_FAST, phoneid, 196 imethod, arg1, arg2, arg3, arg4); 197 198 ipc_finish_async(callid, phoneid, call); 199 } 200 201 /** Asynchronous call transmitting the entire payload. 202 * 203 * Note that this function is a void function. 204 * 205 * During normal operation, answering this call will trigger the callback. 206 * In case of fatal error, the callback handler is called with the proper 207 * error code. If the call cannot be temporarily made, it is queued. 208 * 209 * @param phoneid Phone handle for the call. 210 * @param imethod Requested interface and method. 211 * @param arg1 Service-defined payload argument. 212 * @param arg2 Service-defined payload argument. 213 * @param arg3 Service-defined payload argument. 214 * @param arg4 Service-defined payload argument. 215 * @param arg5 Service-defined payload argument. 216 * @param private Argument to be passed to the answer/error callback. 217 * @param callback Answer or error callback. 218 */ 219 void ipc_call_async_slow(int phoneid, sysarg_t imethod, sysarg_t arg1, 220 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, void *private, 221 ipc_async_callback_t callback) 133 222 { 134 223 async_call_t *call = ipc_prepare_async(private, callback); … … 136 225 return; 137 226 138 int rc = (int) __SYSCALL6(SYS_IPC_CALL_ASYNC_FAST, phandle, imethod, arg1, 139 arg2, arg3, (sysarg_t) call); 140 141 ipc_finish_async(rc, call); 142 } 143 144 /** Asynchronous call transmitting the entire payload. 145 * 146 * Note that this function is a void function. 147 * 148 * During normal operation, answering this call will trigger the callback. 149 * In case of fatal error, the callback handler is called with the proper 150 * error code. If the call cannot be temporarily made, it is queued. 151 * 152 * @param phandle Phone handle for the call. 153 * @param imethod Requested interface and method. 154 * @param arg1 Service-defined payload argument. 155 * @param arg2 Service-defined payload argument. 156 * @param arg3 Service-defined payload argument. 157 * @param arg4 Service-defined payload argument. 158 * @param arg5 Service-defined payload argument. 159 * @param private Argument to be passed to the answer/error callback. 160 * @param callback Answer or error callback. 161 */ 162 void ipc_call_async_slow(int phandle, sysarg_t imethod, sysarg_t arg1, 163 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, void *private, 164 ipc_async_callback_t callback) 165 { 166 async_call_t *call = ipc_prepare_async(private, callback); 167 if (!call) 168 return; 169 170 IPC_SET_IMETHOD(call->msg.data, imethod); 171 IPC_SET_ARG1(call->msg.data, arg1); 172 IPC_SET_ARG2(call->msg.data, arg2); 173 IPC_SET_ARG3(call->msg.data, arg3); 174 IPC_SET_ARG4(call->msg.data, arg4); 175 IPC_SET_ARG5(call->msg.data, arg5); 176 177 int rc = (int) __SYSCALL3(SYS_IPC_CALL_ASYNC_SLOW, phandle, 178 (sysarg_t) &call->msg.data, (sysarg_t) call); 179 180 ipc_finish_async(rc, call); 227 IPC_SET_IMETHOD(call->u.msg.data, imethod); 228 IPC_SET_ARG1(call->u.msg.data, arg1); 229 IPC_SET_ARG2(call->u.msg.data, arg2); 230 IPC_SET_ARG3(call->u.msg.data, arg3); 231 IPC_SET_ARG4(call->u.msg.data, arg4); 232 IPC_SET_ARG5(call->u.msg.data, arg5); 233 234 /* 235 * We need to make sure that we get callid 236 * before another threadaccesses the queue again. 237 */ 238 239 futex_lock(&ipc_futex); 240 ipc_callid_t callid = 241 ipc_call_async_internal(phoneid, &call->u.msg.data); 242 243 ipc_finish_async(callid, phoneid, call); 181 244 } 182 245 … … 186 249 * registers. If you need to return more, use the ipc_answer_slow() instead. 187 250 * 188 * @param c handle Handleof the call being answered.189 * @param retval 190 * @param arg1 191 * @param arg2 192 * @param arg3 193 * @param arg4 251 * @param callid Hash of the call being answered. 252 * @param retval Return value. 253 * @param arg1 First return argument. 254 * @param arg2 Second return argument. 255 * @param arg3 Third return argument. 256 * @param arg4 Fourth return argument. 194 257 * 195 258 * @return Zero on success. … … 197 260 * 198 261 */ 199 int ipc_answer_fast(cap_handle_t chandle, int retval, sysarg_t arg1,262 sysarg_t ipc_answer_fast(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1, 200 263 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4) 201 264 { 202 return (int) __SYSCALL6(SYS_IPC_ANSWER_FAST, chandle, (sysarg_t) retval, arg1, arg2,203 arg 3, arg4);265 return __SYSCALL6(SYS_IPC_ANSWER_FAST, callid, retval, arg1, arg2, arg3, 266 arg4); 204 267 } 205 268 206 269 /** Answer received call (entire payload). 207 270 * 208 * @param c handle Handleof the call being answered.209 * @param retval 210 * @param arg1 211 * @param arg2 212 * @param arg3 213 * @param arg4 214 * @param arg5 271 * @param callid Hash of the call being answered. 272 * @param retval Return value. 273 * @param arg1 First return argument. 274 * @param arg2 Second return argument. 275 * @param arg3 Third return argument. 276 * @param arg4 Fourth return argument. 277 * @param arg5 Fifth return argument. 215 278 * 216 279 * @return Zero on success. … … 218 281 * 219 282 */ 220 int ipc_answer_slow(cap_handle_t chandle, int retval, sysarg_t arg1,283 sysarg_t ipc_answer_slow(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1, 221 284 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5) 222 285 { … … 230 293 IPC_SET_ARG5(data, arg5); 231 294 232 return (int) __SYSCALL2(SYS_IPC_ANSWER_SLOW, chandle, (sysarg_t) &data); 295 return __SYSCALL2(SYS_IPC_ANSWER_SLOW, callid, (sysarg_t) &data); 296 } 297 298 /** Try to dispatch queued calls from the async queue. 299 * 300 */ 301 static void dispatch_queued_calls(void) 302 { 303 /** @todo 304 * Integrate intelligently ipc_futex so that it is locked during 305 * ipc_call_async_*() until it is added to dispatched_calls. 306 */ 307 308 futex_down(&async_futex); 309 310 while (!list_empty(&queued_calls)) { 311 async_call_t *call = 312 list_get_instance(list_first(&queued_calls), async_call_t, list); 313 ipc_callid_t callid = 314 ipc_call_async_internal(call->u.msg.phoneid, &call->u.msg.data); 315 316 list_remove(&call->list); 317 318 futex_up(&async_futex); 319 320 assert(call->fid); 321 fibril_add_ready(call->fid); 322 323 if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) { 324 if (call->callback) 325 call->callback(call->private, ENOENT, NULL); 326 327 free(call); 328 } else { 329 call->u.callid = callid; 330 331 futex_lock(&ipc_futex); 332 list_append(&call->list, &dispatched_calls); 333 futex_unlock(&ipc_futex); 334 } 335 336 futex_down(&async_futex); 337 } 338 339 futex_up(&async_futex); 233 340 } 234 341 235 342 /** Handle received answer. 236 343 * 237 * @param data Call data of the answer. 238 */ 239 static void handle_answer(ipc_call_t *data) 240 { 241 async_call_t *call = data->label; 242 243 if (!call) 244 return; 245 246 if (call->callback) 247 call->callback(call->private, IPC_GET_RETVAL(*data), data); 248 free(call); 344 * Find the hash of the answer and call the answer callback. 345 * 346 * The answer has the same hash as the request OR'ed with 347 * the IPC_CALLID_ANSWERED bit. 348 * 349 * @todo Use hash table. 350 * 351 * @param callid Hash of the received answer. 352 * @param data Call data of the answer. 353 * 354 */ 355 static void handle_answer(ipc_callid_t callid, ipc_call_t *data) 356 { 357 callid &= ~IPC_CALLID_ANSWERED; 358 359 futex_lock(&ipc_futex); 360 361 link_t *item; 362 for (item = dispatched_calls.head.next; item != &dispatched_calls.head; 363 item = item->next) { 364 async_call_t *call = 365 list_get_instance(item, async_call_t, list); 366 367 if (call->u.callid == callid) { 368 list_remove(&call->list); 369 370 futex_unlock(&ipc_futex); 371 372 if (call->callback) 373 call->callback(call->private, 374 IPC_GET_RETVAL(*data), data); 375 376 free(call); 377 return; 378 } 379 } 380 381 futex_unlock(&ipc_futex); 249 382 } 250 383 251 384 /** Wait for first IPC call to come. 252 *253 * @param call Incoming call storage.254 * @param usec Timeout in microseconds255 * @param flags Flags passed to SYS_IPC_WAIT (blocking, nonblocking).256 * @param[out] out_handle Call handle.257 *258 * @return Error code.259 */260 int ipc_wait_cycle(ipc_call_t *call, sysarg_t usec, unsigned int flags)261 {262 int rc = (int) __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, flags);263 264 /* Handle received answers */265 if ((rc == EOK) && (call->cap_handle == CAP_NIL) &&266 (call->flags & IPC_CALL_ANSWERED)) {267 handle_answer(call);268 }269 270 return rc;271 }272 273 /** Interrupt one thread of this task from waiting for IPC.274 *275 */276 void ipc_poke(void)277 {278 __SYSCALL0(SYS_IPC_POKE);279 }280 281 /** Wait for first IPC call to come.282 *283 * Only requests are returned, answers are processed internally.284 385 * 285 386 * @param call Incoming call storage. 286 387 * @param usec Timeout in microseconds 287 * 288 * @return Error code. 289 * 290 */ 291 int ipc_wait_for_call_timeout(ipc_call_t *call, sysarg_t usec) 292 { 293 int rc; 388 * @param flags Flags passed to SYS_IPC_WAIT (blocking, nonblocking). 389 * 390 * @return Hash of the call. Note that certain bits have special 391 * meaning: IPC_CALLID_ANSWERED is set in an answer 392 * and IPC_CALLID_NOTIFICATION is used for notifications. 393 * 394 */ 395 ipc_callid_t ipc_wait_cycle(ipc_call_t *call, sysarg_t usec, 396 unsigned int flags) 397 { 398 ipc_callid_t callid = 399 __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, flags); 400 401 /* Handle received answers */ 402 if (callid & IPC_CALLID_ANSWERED) { 403 handle_answer(callid, call); 404 dispatch_queued_calls(); 405 } 406 407 return callid; 408 } 409 410 /** Interrupt one thread of this task from waiting for IPC. 411 * 412 */ 413 void ipc_poke(void) 414 { 415 __SYSCALL0(SYS_IPC_POKE); 416 } 417 418 /** Wait for first IPC call to come. 419 * 420 * Only requests are returned, answers are processed internally. 421 * 422 * @param call Incoming call storage. 423 * @param usec Timeout in microseconds 424 * 425 * @return Hash of the call. 426 * 427 */ 428 ipc_callid_t ipc_wait_for_call_timeout(ipc_call_t *call, sysarg_t usec) 429 { 430 ipc_callid_t callid; 294 431 295 432 do { 296 rc= ipc_wait_cycle(call, usec, SYNCH_FLAGS_NONE);297 } while ( (rc == EOK) && (call->cap_handle == CAP_NIL) && (call->flags & IPC_CALL_ANSWERED));298 299 return rc;433 callid = ipc_wait_cycle(call, usec, SYNCH_FLAGS_NONE); 434 } while (callid & IPC_CALLID_ANSWERED); 435 436 return callid; 300 437 } 301 438 … … 304 441 * Only requests are returned, answers are processed internally. 305 442 * 306 * @param call 307 * 308 * @return Error code.309 * 310 */ 311 i nt ipc_trywait_for_call(ipc_call_t *call)312 { 313 i nt rc;443 * @param call Incoming call storage. 444 * 445 * @return Hash of the call. 446 * 447 */ 448 ipc_callid_t ipc_trywait_for_call(ipc_call_t *call) 449 { 450 ipc_callid_t callid; 314 451 315 452 do { 316 rc= ipc_wait_cycle(call, SYNCH_NO_TIMEOUT,453 callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT, 317 454 SYNCH_FLAGS_NON_BLOCKING); 318 } while ( (rc == EOK) && (call->cap_handle == CAP_NIL) && (call->flags & IPC_CALL_ANSWERED));319 320 return rc;455 } while (callid & IPC_CALLID_ANSWERED); 456 457 return callid; 321 458 } 322 459 323 460 /** Hang up a phone. 324 461 * 325 * @param ph andleHandle of the phone to be hung up.326 * 327 * @return Zero on success or anerror code.328 * 329 */ 330 int ipc_hangup( cap_handle_t phandle)331 { 332 return (int) __SYSCALL1(SYS_IPC_HANGUP, phandle);462 * @param phoneid Handle of the phone to be hung up. 463 * 464 * @return Zero on success or a negative error code. 465 * 466 */ 467 int ipc_hangup(int phoneid) 468 { 469 return __SYSCALL1(SYS_IPC_HANGUP, phoneid); 333 470 } 334 471 335 472 /** Forward a received call to another destination. 336 473 * 337 * For non-system methods, the old method, arg1 and arg2 are rewritten by the338 * new values. For system methods, the new method, arg1 and arg2 are written to339 * the old arg1, arg2 and arg3, respectivelly. Calls with immutable methods are340 * forwarded verbatim.341 * 342 * @param c handle Handleof the call to forward.343 * @param ph andlePhone handle to use for forwarding.344 * @param imethod 345 * @param arg1 346 * @param arg2 347 * @param mode 348 * 349 * @return 350 * 351 */ 352 int ipc_forward_fast( cap_handle_t chandle, cap_handle_t phandle,353 sysarg_t imethod, sysarg_targ1, sysarg_t arg2, unsigned int mode)354 { 355 return (int) __SYSCALL6(SYS_IPC_FORWARD_FAST, chandle, phandle, imethod, arg1,474 * For non-system methods, the old method, arg1 and arg2 are rewritten 475 * by the new values. For system methods, the new method, arg1 and arg2 476 * are written to the old arg1, arg2 and arg3, respectivelly. Calls with 477 * immutable methods are forwarded verbatim. 478 * 479 * @param callid Hash of the call to forward. 480 * @param phoneid Phone handle to use for forwarding. 481 * @param imethod New interface and method for the forwarded call. 482 * @param arg1 New value of the first argument for the forwarded call. 483 * @param arg2 New value of the second argument for the forwarded call. 484 * @param mode Flags specifying mode of the forward operation. 485 * 486 * @return Zero on success or an error code. 487 * 488 */ 489 int ipc_forward_fast(ipc_callid_t callid, int phoneid, sysarg_t imethod, 490 sysarg_t arg1, sysarg_t arg2, unsigned int mode) 491 { 492 return __SYSCALL6(SYS_IPC_FORWARD_FAST, callid, phoneid, imethod, arg1, 356 493 arg2, mode); 357 494 } 358 495 359 int ipc_forward_slow( cap_handle_t chandle, cap_handle_t phandle,360 sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,361 sysarg_t arg4, sysarg_t arg5,unsigned int mode)496 int ipc_forward_slow(ipc_callid_t callid, int phoneid, sysarg_t imethod, 497 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, 498 unsigned int mode) 362 499 { 363 500 ipc_call_t data; … … 370 507 IPC_SET_ARG5(data, arg5); 371 508 372 return (int) __SYSCALL4(SYS_IPC_FORWARD_SLOW, chandle, phandle,373 (sysarg_t) &data,mode);509 return __SYSCALL4(SYS_IPC_FORWARD_SLOW, callid, phoneid, (sysarg_t) &data, 510 mode); 374 511 } 375 512 … … 377 514 * 378 515 */ 379 int ipc_connect_kbox(task_id_t id, cap_handle_t *phone) 380 { 381 return (int) __SYSCALL2(SYS_IPC_CONNECT_KBOX, (sysarg_t) &id, (sysarg_t) phone); 516 int ipc_connect_kbox(task_id_t id) 517 { 518 #ifdef __32_BITS__ 519 sysarg64_t arg = (sysarg64_t) id; 520 return __SYSCALL1(SYS_IPC_CONNECT_KBOX, (sysarg_t) &arg); 521 #endif 522 523 #ifdef __64_BITS__ 524 return __SYSCALL1(SYS_IPC_CONNECT_KBOX, (sysarg_t) id); 525 #endif 382 526 } 383 527
Note:
See TracChangeset
for help on using the changeset viewer.