Changeset 8b243f2 in mainline for uspace/libc/generic/ipc.c
- Timestamp:
- 2007-06-17T19:34:36Z (18 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- bd72c3e9
- Parents:
- 4680ef5
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/libc/generic/ipc.c
r4680ef5 r8b243f2 52 52 #include <psthread.h> 53 53 54 /** Structure used for keeping track of sent async msgs 55 * and queing unsent msgs 56 * 54 /** Structure used for keeping track of sent asynchronous calls and queing 55 * unsent calls. 57 56 */ 58 57 typedef struct { … … 67 66 int phoneid; 68 67 } msg; 69 } u;70 pstid_t ptid; /**< Thread waiting for sending this msg*/68 } u; 69 pstid_t ptid; /**< Pseudothread waiting for sending this call. */ 71 70 } async_call_t; 72 71 73 72 LIST_INITIALIZE(dispatched_calls); 74 73 75 /* queued_calls is protcted by async_futex, because if the76 * call cannot be sent into kernel, async framework is used77 * automatically78 * /79 LIST_INITIALIZE(queued_calls); /**< List of async calls that were not accepted 80 * by kernel */ 74 /** List of asynchronous calls that were not accepted by kernel. 75 * 76 * It is protected by async_futex, because if the call cannot be sent into the 77 * kernel, the async framework is used automatically. 78 */ 79 LIST_INITIALIZE(queued_calls); 81 80 82 81 static atomic_t ipc_futex = FUTEX_INITIALIZER; 83 82 84 int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1, 85 ipcarg_t *result) 83 /** Make a fast synchronous call. 84 * 85 * Only one payload argument can be passed using this function. However, this 86 * function is faster than the generic ipc_call_sync_3(). 87 * 88 * @param phoneid Phone handle for the call. 89 * @param method Requested method. 90 * @param arg1 Service-defined payload argument. 91 * @param result If non-NULL, the return ARG1 will be stored there. 92 * 93 * @return Negative values represent errors returned by IPC. 94 * Otherwise the RETVAL of the answer is returned. 95 */ 96 int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t *result) 86 97 { 87 98 ipc_call_t resdata; … … 89 100 90 101 callres = __SYSCALL4(SYS_IPC_CALL_SYNC_FAST, phoneid, method, arg1, 91 (sysarg_t)&resdata);102 (sysarg_t) &resdata); 92 103 if (callres) 93 104 return callres; … … 97 108 } 98 109 99 int ipc_call_sync_3(int phoneid, ipcarg_t method, ipcarg_t arg1, 100 ipcarg_t arg2, ipcarg_t arg3, 101 ipcarg_t *result1, ipcarg_t *result2, ipcarg_t *result3) 110 /** Make a synchronous call transmitting 3 arguments of payload. 111 * 112 * @param phoneid Phone handle for the call. 113 * @param method Requested method. 114 * @param arg1 Service-defined payload argument. 115 * @param arg2 Service-defined payload argument. 116 * @param arg3 Service-defined payload argument. 117 * @param result1 If non-NULL, storage for the first return argument. 118 * @param result2 If non-NULL, storage for the second return argument. 119 * @param result3 If non-NULL, storage for the third return argument. 120 * 121 * @return Negative value means IPC error. 122 * Otherwise the RETVAL of the answer. 123 */ 124 int ipc_call_sync_3(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2, 125 ipcarg_t arg3, ipcarg_t *result1, ipcarg_t *result2, ipcarg_t *result3) 102 126 { 103 127 ipc_call_t data; … … 109 133 IPC_SET_ARG3(data, arg3); 110 134 111 callres = __SYSCALL3(SYS_IPC_CALL_SYNC, phoneid, (sysarg_t) &data,112 (sysarg_t)&data);135 callres = __SYSCALL3(SYS_IPC_CALL_SYNC, phoneid, (sysarg_t) &data, 136 (sysarg_t) &data); 113 137 if (callres) 114 138 return callres; … … 123 147 } 124 148 125 /** Syscall to send asynchronous message */ 126 static ipc_callid_t _ipc_call_async(int phoneid, ipc_call_t *data) 127 { 128 return __SYSCALL2(SYS_IPC_CALL_ASYNC, phoneid, (sysarg_t)data); 129 } 130 131 /** Prolog to ipc_async_send functions */ 132 static inline async_call_t *ipc_prepare_async(void *private, ipc_async_callback_t callback) 149 /** Syscall to send asynchronous message. 150 * 151 * @param phoneid Phone handle for the call. 152 * @param data Call data with the request. 153 * 154 * @return Hash of the call or an error code. 155 */ 156 static ipc_callid_t _ipc_call_async(int phoneid, ipc_call_t *data) 157 { 158 return __SYSCALL2(SYS_IPC_CALL_ASYNC, phoneid, (sysarg_t) data); 159 } 160 161 /** Prolog to ipc_call_async_*() functions. 162 * 163 * @param private Argument for the answer/error callback. 164 * @param callback Answer/error callback. 165 * 166 * @return New, partially initialized async_call structure or NULL. 167 */ 168 static inline async_call_t *ipc_prepare_async(void *private, 169 ipc_async_callback_t callback) 133 170 { 134 171 async_call_t *call; … … 146 183 } 147 184 148 /** Epilogue of ipc_async_send functions */ 149 static inline void ipc_finish_async(ipc_callid_t callid, int phoneid, 150 async_call_t *call, int can_preempt) 185 /** Epilogue of ipc_call_async_*() functions. 186 * 187 * @param callid Value returned by the SYS_IPC_CALL_ASYNC_* syscall. 188 * @param phoneid Phone handle through which the call was made. 189 * @param call async_call structure returned by ipc_prepare_async(). 190 * @param can_preempt If non-zero, the current pseudo thread can be preempted 191 * in this call. 192 */ 193 static inline void ipc_finish_async(ipc_callid_t callid, int phoneid, 194 async_call_t *call, int can_preempt) 151 195 { 152 196 if (!call) { /* Nothing to do regardless if failed or not */ … … 183 227 } 184 228 call->u.callid = callid; 185 /* Add call to list of dispatched calls */229 /* Add call to the list of dispatched calls */ 186 230 list_append(&call->list, &dispatched_calls); 187 231 futex_up(&ipc_futex); … … 189 233 } 190 234 191 /** Send asynchronous message 192 * 193 * - if fatal error, call callback handler with proper error code 194 * - if message cannot be temporarily sent, add to queue 235 /** Make a fast asynchronous call. 236 * 237 * This function can only handle two arguments of payload. It is, however, 238 * faster than the more generic ipc_call_async_3(). 239 * 240 * Note that this function is a void function. 241 * During normal opertation, answering this call will trigger the callback. 242 * In case of fatal error, call the callback handler with the proper error code. 243 * If the call cannot be temporarily made, queue it. 244 * 245 * @param phoneid Phone handle for the call. 246 * @param method Requested method. 247 * @param arg1 Service-defined payload argument. 248 * @param arg2 Service-defined payload argument. 249 * @param private Argument to be passed to the answer/error callback. 250 * @param callback Answer or error callback. 251 * @param can_preempt If non-zero, the current pseudo thread will be preempted 252 * in case the kernel temporarily refuses to accept more 253 * asynchronous calls. 195 254 */ 196 255 void ipc_call_async_2(int phoneid, ipcarg_t method, ipcarg_t arg1, 197 ipcarg_t arg2, void *private,198 ipc_async_callback_t callback,int can_preempt)256 ipcarg_t arg2, void *private, ipc_async_callback_t callback, 257 int can_preempt) 199 258 { 200 259 async_call_t *call = NULL; … … 207 266 } 208 267 209 /* We need to make sure that we get callid before 210 * another thread accesses the queue again */ 268 /* 269 * We need to make sure that we get callid before another thread 270 * accesses the queue again. 271 */ 211 272 futex_down(&ipc_futex); 212 callid = __SYSCALL4(SYS_IPC_CALL_ASYNC_FAST, phoneid, method, arg1, arg2); 273 callid = __SYSCALL4(SYS_IPC_CALL_ASYNC_FAST, phoneid, method, arg1, 274 arg2); 213 275 214 276 if (callid == IPC_CALLRET_TEMPORARY) { … … 225 287 } 226 288 227 /** Send asynchronous message 228 * 229 * - if fatal error, call callback handler with proper error code 230 * - if message cannot be temporarily sent, add to queue 289 /** Make an asynchronous call transmitting the entire payload. 290 * 291 * Note that this function is a void function. 292 * During normal opertation, answering this call will trigger the callback. 293 * In case of fatal error, call the callback handler with the proper error code. 294 * If the call cannot be temporarily made, queue it. 295 * 296 * @param phoneid Phone handle for the call. 297 * @param method Requested method. 298 * @param arg1 Service-defined payload argument. 299 * @param arg2 Service-defined payload argument. 300 * @param arg3 Service-defined payload argument. 301 * @param private Argument to be passed to the answer/error callback. 302 * @param callback Answer or error callback. 303 * @param can_preempt If non-zero, the current pseudo thread will be preempted 304 * in case the kernel temporarily refuses to accept more 305 * asynchronous calls. 306 * 231 307 */ 232 308 void ipc_call_async_3(int phoneid, ipcarg_t method, ipcarg_t arg1, 233 ipcarg_t arg2, ipcarg_t arg3, void *private,234 ipc_async_callback_t callback,int can_preempt)309 ipcarg_t arg2, ipcarg_t arg3, void *private, ipc_async_callback_t callback, 310 int can_preempt) 235 311 { 236 312 async_call_t *call; … … 245 321 IPC_SET_ARG2(call->u.msg.data, arg2); 246 322 IPC_SET_ARG3(call->u.msg.data, arg3); 247 /* We need to make sure that we get callid before 248 * another thread accesses the queue again */ 323 /* 324 * We need to make sure that we get callid before another thread accesses 325 * the queue again. 326 */ 249 327 futex_down(&ipc_futex); 250 328 callid = _ipc_call_async(phoneid, &call->u.msg.data); … … 254 332 255 333 256 /** Send a fast answer to a received call.257 * 258 * The fast answer makes use of passing retval and first two arguments in registers.259 * If you need to return more, use the ipc_answer() instead.260 * 261 * @param callid IDof the call being answered.262 * @param retval 263 * @param arg1 264 * @param arg2 265 * 266 * @return 334 /** Answer a received call - fast version. 335 * 336 * The fast answer makes use of passing retval and first two arguments in 337 * registers. If you need to return more, use the ipc_answer() instead. 338 * 339 * @param callid Hash of the call being answered. 340 * @param retval Return value. 341 * @param arg1 First return argument. 342 * @param arg2 Second return argument. 343 * 344 * @return Zero on success or a value from @ref errno.h on failure. 267 345 */ 268 346 ipcarg_t ipc_answer_fast(ipc_callid_t callid, ipcarg_t retval, ipcarg_t arg1, 269 347 ipcarg_t arg2) 270 348 { 271 349 return __SYSCALL4(SYS_IPC_ANSWER_FAST, callid, retval, arg1, arg2); 272 350 } 273 351 274 /** Send a full answer to a received call. 275 * 276 * @param callid ID of the call being answered. 277 * @param call Call data. Must be already initialized by the responder. 278 * 279 * @return Zero on success or a value from @ref errno.h on failure. 352 /** Answer a received call - full version. 353 * 354 * @param callid Hash of the call being answered. 355 * @param call Call structure with the answer. 356 * Must be already initialized by the responder. 357 * 358 * @return Zero on success or a value from @ref errno.h on failure. 280 359 */ 281 360 ipcarg_t ipc_answer(ipc_callid_t callid, ipc_call_t *call) … … 285 364 286 365 287 /** Try to dispatch que ed calls from async queue*/366 /** Try to dispatch queued calls from the async queue. */ 288 367 static void try_dispatch_queued_calls(void) 289 368 { … … 291 370 ipc_callid_t callid; 292 371 293 /* TODO: integrate intelligently ipc_futex, so that it294 * is locked during ipc_call_async, until it is added295 * to dispatched_calls372 /** @todo 373 * Integrate intelligently ipc_futex, so that it is locked during 374 * ipc_call_async_*(), until it is added to dispatched_calls. 296 375 */ 297 376 futex_down(&async_futex); 298 377 while (!list_empty(&queued_calls)) { 299 call = list_get_instance(queued_calls.next, async_call_t, 300 list); 301 302 callid = _ipc_call_async(call->u.msg.phoneid, 303 &call->u.msg.data); 378 call = list_get_instance(queued_calls.next, async_call_t, list); 379 callid = _ipc_call_async(call->u.msg.phoneid, &call->u.msg.data); 304 380 if (callid == IPC_CALLRET_TEMPORARY) { 305 381 break; … … 326 402 } 327 403 328 /** Handle received answer 329 * 330 * TODO: Make it use hash table 331 * 332 * @param callid Callid (with first bit set) of the answered call 404 /** Handle a received answer. 405 * 406 * Find the hash of the answer and call the answer callback. 407 * 408 * @todo Make it use hash table. 409 * 410 * @param callid Hash of the received answer. 411 * The answer has the same hash as the request OR'ed with 412 * the IPC_CALLID_ANSWERED bit. 413 * @param data Call data of the answer. 333 414 */ 334 415 static void handle_answer(ipc_callid_t callid, ipc_call_t *data) … … 341 422 futex_down(&ipc_futex); 342 423 for (item = dispatched_calls.next; item != &dispatched_calls; 343 424 item = item->next) { 344 425 call = list_get_instance(item, async_call_t, list); 345 426 if (call->u.callid == callid) { … … 348 429 if (call->callback) 349 430 call->callback(call->private, 350 IPC_GET_RETVAL(*data), 351 data); 431 IPC_GET_RETVAL(*data), data); 352 432 free(call); 353 433 return; … … 355 435 } 356 436 futex_up(&ipc_futex); 357 /* We may get here after async_msg, which doesn't register any callback */ 358 } 359 360 361 /** One cycle of ipc wait for call call 362 * 363 * - dispatch ASYNC reoutines in the background 364 * @param call Space where the message is stored 365 * @param usec Timeout in microseconds 366 * @param flags Flags passed to SYS_IPC_WAIT (blocking, nonblocking) 367 * @return Callid of the answer. 437 } 438 439 440 /** Wait for a first call to come. 441 * 442 * @param call Storage where the incoming call data will be stored. 443 * @param usec Timeout in microseconds 444 * @param flags Flags passed to SYS_IPC_WAIT (blocking, nonblocking). 445 * 446 * @return Hash of the call. Note that certain bits have special 447 * meaning. IPC_CALLID_ANSWERED will be set in an answer 448 * and IPC_CALLID_NOTIFICATION is used for notifications. 449 * 368 450 */ 369 451 ipc_callid_t ipc_wait_cycle(ipc_call_t *call, uint32_t usec, int flags) … … 383 465 /** Wait some time for an IPC call. 384 466 * 385 * - dispatch ASYNC reoutines in the background 386 * 387 * @param call Space where the message is stored 388 * @param usec Timeout in microseconds. 389 * @return Callid of the answer. 467 * The call will return after an answer is received. 468 * 469 * @param call Storage where the incoming call data will be stored. 470 * @param usec Timeout in microseconds. 471 * 472 * @return Hash of the answer. 390 473 */ 391 474 ipc_callid_t ipc_wait_for_call_timeout(ipc_call_t *call, uint32_t usec) … … 402 485 /** Check if there is an IPC call waiting to be picked up. 403 486 * 404 * - dispatch ASYNC reoutines in the background 405 * 406 * @param call Space where the message is stored 407 * @return Callid of the answer. 487 * @param call Storage where the incoming call will be stored. 488 * @return Hash of the answer. 408 489 */ 409 490 ipc_callid_t ipc_trywait_for_call(ipc_call_t *call) … … 412 493 413 494 do { 414 callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NON_BLOCKING); 495 callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT, 496 SYNCH_FLAGS_NON_BLOCKING); 415 497 } while (callid & IPC_CALLID_ANSWERED); 416 498 … … 420 502 /** Ask destination to do a callback connection. 421 503 * 422 * @param phoneid Phone ID used for contacting the other side. 504 * @param phoneid Phone handle used for contacting the other side. 505 * @param arg1 Service-defined argument. 506 * @param arg2 Service-defined argument. 507 * @param phonehash Storage where the library will store an opaque 508 * identifier of the phone that will be used for incoming 509 * calls. This identifier can be used for connection 510 * tracking. 511 * 512 * @return Zero on success or a negative error code. 513 */ 514 int ipc_connect_to_me(int phoneid, int arg1, int arg2, ipcarg_t *phonehash) 515 { 516 return ipc_call_sync_3(phoneid, IPC_M_CONNECT_TO_ME, arg1, arg2, 0, 0, 0, 517 phonehash); 518 } 519 520 /** Ask through phone for a new connection to some service. 521 * 522 * @param phoneid Phone handle used for contacting the other side. 423 523 * @param arg1 User defined argument. 424 524 * @param arg2 User defined argument. 425 * @param phonehash Pointer to a place where the library will store an opaque 426 * identifier of the phone that will be used for incoming 427 * calls. 428 * @return Zero on success or a negative error code. 429 */ 430 int ipc_connect_to_me(int phoneid, int arg1, int arg2, ipcarg_t *phonehash) 431 { 432 return ipc_call_sync_3(phoneid, IPC_M_CONNECT_TO_ME, arg1, arg2, 0, 0, 0, 433 phonehash); 434 } 435 436 /** Ask through phone for a new connection to some service. 437 * 438 * @param phoneid Phone ID used for contacting the other side. 439 * @param arg1 User defined argument. 440 * @param arg2 User defined argument. 441 * 442 * @return New phone ID on success or a negative error code. 525 * 526 * @return New phone handle on success or a negative error code. 443 527 */ 444 528 int ipc_connect_me_to(int phoneid, int arg1, int arg2) … … 454 538 } 455 539 456 /* Hang up specified phone */ 540 /** Hang up a phone. 541 * 542 * @param phoneid Handle of the phone to be hung up. 543 * 544 * @return Zero on success or a negative error code. 545 */ 457 546 int ipc_hangup(int phoneid) 458 547 { … … 462 551 /** Register IRQ notification. 463 552 * 464 * @param inr 465 * @param devno 466 * @param method 467 * @param ucode 468 * 469 * @return 553 * @param inr IRQ number. 554 * @param devno Device number of the device generating inr. 555 * @param method Use this method for notifying me. 556 * @param ucode Top-half pseudocode handler. 557 * 558 * @return Value returned by the kernel. 470 559 */ 471 560 int ipc_register_irq(int inr, int devno, int method, irq_code_t *ucode) 472 561 { 473 return __SYSCALL4(SYS_IPC_REGISTER_IRQ, inr, devno, method, (sysarg_t) ucode); 562 return __SYSCALL4(SYS_IPC_REGISTER_IRQ, inr, devno, method, 563 (sysarg_t) ucode); 474 564 } 475 565 476 566 /** Unregister IRQ notification. 477 567 * 478 * @param inr 479 * @param devno 480 * 481 * @return 568 * @param inr IRQ number. 569 * @param devno Device number of the device generating inr. 570 * 571 * @return Value returned by the kernel. 482 572 */ 483 573 int ipc_unregister_irq(int inr, int devno) … … 486 576 } 487 577 578 /** Forward a received call to another destination. 579 * 580 * @param callid Hash of the call to forward. 581 * @param phoneid Phone handle to use for forwarding. 582 * @param method New method for the forwarded call. 583 * @param arg1 New value of the first argument for the forwarded call. 584 * 585 * @return Zero on success or an error code. 586 * 587 * For non-system methods, the old method and arg1 are rewritten by the new 588 * values. For system methods, the new method and arg1 are written to the old 589 * arg1 and arg2, respectivelly. 590 */ 488 591 int ipc_forward_fast(ipc_callid_t callid, int phoneid, int method, ipcarg_t arg1) 489 592 {
Note:
See TracChangeset
for help on using the changeset viewer.