Changes between Version 7 and Version 8 of IPC


Ignore:
Timestamp:
2018-06-21T14:16:18Z (6 years ago)
Author:
Martin Decky
Comment:

update for current async framework API

Legend:

Unmodified
Added
Removed
Modified
  • IPC

    v7 v8  
    197197
    198198{{{
    199         async_answer_1(rid, EOK, fd);
    200 }}}
    201 
    202 In this example, ''rid'' is the capability of the received call, ''EOK'' is the return value and ''fd'' is the only return argument.
     199        async_answer_1(callid, EOK, fd);
     200}}}
     201
     202In this example, ''callid'' is the capability of the received call, ''EOK'' is the return value and ''fd'' is the only return argument.
    203203
    204204== Passing large data via IPC == #IpcDataCopy
     
    222222
    223223{{{
    224 #include <ipc/ipc.h>
    225 #include <async.h>
    226 ...
    227 int vfs_phone;
    228 int rc;
    229 char *pa;
    230 size_t pa_len;
    231 ...
    232         rc = async_data_write_start(vfs_phone, pa, pa_len);
    233         if (rc != EOK) {
    234                 /* an error or the recipient denied the bid */
    235         }
    236 }}}
    237 
    238 The ''pa'' and ''pa_len'' arguments, respectively, specify the source address and the suggested number of bytes to transfer, respectively.
     224#include <async.h>
     225...
     226        char *pa;
     227        size_t pa_len;
     228...
     229        async_exch_t *exch = async_exchange_begin(session);
     230        if (exch == NULL) {
     231                /* Handle error creating an exchange */
     232        }
     233
     234        int rc = async_data_write_start(exch, pa, pa_len);
     235        async_exchange_end(exch);
     236
     237        if (rc != EOK) {
     238                /* Error or the recipient denied the bid */
     239        }
     240}}}
     241
     242The ''pa'' and ''pa_len'' arguments specify the source address and the suggested number of bytes to transfer, respectively.
    239243The recipient will be able to determine the size parameter of the transfer in the receive phase:
    240244
    241245{{{
    242 #include <ipc/ipc.h>
    243 #include <async.h>
    244 ...
    245 ipc_callid_t callid;
    246 size_t len;
    247 ...
    248         if (!async_data_write_receive(&callid, &len)) {
    249                 /* protocol error - the sender is not sending data */
    250         }
    251         /* success, the receive phase is complete */
     246#include <async.h>
     247...
     248        ipc_callid_t callid;
     249        size_t len;
     250        if (!async_data_write_receive(&callid, &len)) {
     251                /* Protocol error - the sender is not sending data */
     252        }
     253
     254        /* Success, the receive phase is complete */
    252255}}}
    253256
     
    255258The separation of the receive and the final phase is important, because the recipient can get ready for the transfer (e.g. allocate the required amount of memory).
    256259
    257 Now the recipient is on the cross-roads. It can do one of three things. It can answer the call with a non-zero return code, or it can accept and restrict the size of the
    258 transfer, or it can accept the transfer including the suggested size. The latter two options are achieved like this:
    259 
    260 {{{
    261 char *path;
    262 ...
    263         (void) async_data_write_finalize(callid, path, len);
     260Now the recipient is on the cross-roads. It can do one of three things. It can answer the call with a non-zero return code, or it
     261can accept and restrict the size of the transfer, or it can accept the transfer including the suggested size. The latter two options are achieved like this:
     262
     263{{{
     264        char *path;
     265
     266        /* Allocate the receive buffer */
     267
     268        (void) async_data_write_finalize(callid, path, len);
    264269}}}
    265270
    266271After this call, the data transfer of ''len'' bytes to address ''path'' will be realized. The operation can theoretically fail, so you should check the return value
    267 of ''ipc_data_write_finalize()''. If it is non-zero, then there was an error.
     272of ''async_data_write_finalize()''. If it is non-zero, then there was an error.
    268273
    269274=== Accepting data ===
    270275
    271276When accepting data, the client is the recipient and the server is the sender. The situation is similar to the previous one, the only difference is that the client
    272 specifies the destination address and the largest possible size for the transfer. The server can send less data than requested. In the following example, the ''read()''
    273 function in the standard library is requesting ''nbyte'' worth of data to be read from a file system into the ''buf'' buffer:
    274 
    275 {{{
    276 #include <ipc/ipc.h>
    277 #include <async.h>
    278 ...
    279 int vfs_phone;
    280 void *buf;
    281 size_t nbyte;
    282 ipcarg_t rc;
    283 ...
    284         rc = async_data_read_start(vfs_phone, buf, nbyte);
    285         if (rc != EOK) {
    286                 /* handle error */
    287         }
     277specifies the destination address and the largest possible size for the transfer. The server can send less data than requested. In the following example,
     278the ''read()'' function in the standard library is requesting ''nbyte'' worth of data to be read from a file system into the ''buf'' buffer:
     279
     280{{{
     281#include <async.h>
     282...
     283        async_exch_t *exch = async_exchange_begin(session);
     284        if (exch == NULL) {
     285                /* Handle error creating an exchange */
     286        }
     287
     288        int rc = async_data_read_start(exch, buf, nbyte)
     289        async_exchange_end(exch);
     290
     291        if (rc != EOK) {
     292                /* Error or the recipient denied the bid */
     293        }
    288294}}}
    289295
     
    291297
    292298{{{
    293 #include <ipc/ipc.h>
    294 #include <async.h>
    295 ...
    296 ipc_callid_t callid;
    297 size_t len;
    298 ...
    299         if (!async_data_read_receive(&callid, &len)) {
    300                 /* protocol error - the recipient is not accepting data */
    301         }
    302         /* success, the receive phase is complete */
     299#include <async.h>
     300...
     301        ipc_callid_t callid;
     302        size_t len;
     303        if (!async_data_read_receive(&callid, &len)) {
     304                /* Protocol error - the sender is not accepting data */
     305        }
     306
     307        /* Success, the receive phase is complete */
    303308}}}
    304309
     
    310315}}}
    311316
    312 Here the sender specifies the source address and the actual number of bytes to transfer. After the function call completes, the data has been transfered to the recipient.
    313 Note that the return value of ''ipc_data_read_finalize()'' is, maybe unjustly, ignored.
     317Here the sender specifies the source address and the actual number of bytes to transfer. After the function call completes, the data has been transferred
     318to the recipient. Note that the return value of ''async_data_read_finalize()'' is, maybe unjustly, ignored.
    314319
    315320== Sharing memory via IPC  == #IpcShareMem
    316321
    317 In HelenOS, tasks can share memory only via IPC as the kernel does not provide dedicated system calls for memory sharing. Instead, the tasks negotiate much like in the case of [#IpcDataCopy passing large data]. The negotiation has three phases and is very similar to the previous case:
     322In HelenOS, tasks can share memory only via IPC as the kernel does not provide dedicated system calls for memory sharing. Instead, the tasks negotiate much
     323like in the case of [#IpcDataCopy passing large data]. The negotiation has three phases and is very similar to the previous case:
    318324
    319325 * the initial phase in which the client announces its intention to share memory to or from the recipient,
     
    325331=== Sharing address space area out ===
    326332
    327 When sharing an address space area to other tasks, the client is the sender and the server is the recipient. The client offers one of its address space areas to the server for sharing.
    328 The following code snippet illustrates libblock's ''block_init()'' function offering a part of its address space starting at ''com_area'' to a block device associated with the ''dev_phone'' phone handle:
    329 
    330 {{{
    331 #include <ipc/ipc.h>
    332 #include <async.h>
    333 ...
    334         int rc;
    335         int dev_phone;
    336         void *com_area;
    337 ...
    338         rc = async_share_out_start(dev_phone, com_area,
    339             AS_AREA_READ | AS_AREA_WRITE);
    340         if (rc != EOK) {
    341                 /* handle error */
    342         }
    343 }}}
    344 
    345 This is how the RD server receives the address space area offer made above:
    346 
    347 {{{
    348 #include <ipc/ipc.h>
    349 #include <async.h>
    350 ...
    351         ipc_callid_t callid;
    352         size_t maxblock_size;
    353         int flags;
    354 ...
    355         if (!async_share_out_receive(&callid, &maxblock_size, &flags)) {
    356                 /* handle error */
    357         }
    358 }}}
    359 
    360 After the offer is received, the server has a chance to reject it by answering ''callid'' with an error code distinct from EOK. The reason for denial can be an inappropriate ''maxblock_size'' or non-suitable address space area flags in the ''flags'' variable. If the offer looks good to the server, it will accept it like this:
    361 
    362 {{{
    363         void *fs_va;
    364         ...
    365         (void) async_share_out_finalize(callid, fs_va);
    366 }}}
    367 
    368 Note that the return value of ''ipc_share_out_finalize()'' is maybe unjustly ignored here.
    369 
    370 The kernel will attempt to create the mapping only after the server calls ''ipc_share_out_finalize()''.
     333When sharing an address space area to other tasks, the client is the sender and the server is the recipient. The client offers one of its address space areas
     334to the server for sharing. The following code snippet illustrates libblock's ''block_init()'' function offering a part of its address space starting at
     335''com_area'' to a block device associated with the ''dev_session'' session:
     336
     337{{{
     338#include <async.h>
     339...
     340        async_exch_t *exch = async_exchange_begin(session);
     341        if (exch == NULL) {
     342                /* Handle error creating an exchange */
     343        }
     344
     345        int rc = async_share_out_start(exch, com_area,
     346            AS_AREA_READ | AS_AREA_WRITE);
     347        async_exchange_end(exch);
     348
     349        if (rc != EOK) {
     350                /* Error or the recipient denied the bid */
     351        }
     352}}}
     353
     354This is how the RAM disk server receives the address space area offer made above:
     355
     356{{{
     357#include <async.h>
     358...
     359        ipc_callid_t callid;
     360        size_t len;
     361        int flags;
     362        if (!async_share_out_receive(&callid, &len, &flags)) {
     363                /* Protocol error - the sender is sharing out an area */
     364        }
     365
     366        /* Success, the receive phase is complete */
     367}}}
     368
     369After the offer is received, the server has a chance to reject it by answering ''callid'' with an error code distinct from EOK. The reason for denial can be an inappropriate ''len'' or non-suitable address space area flags in the ''flags'' variable. If the offer looks good to the server, it will accept it like this:
     370
     371{{{
     372        void *fs_va;
     373        (void) async_share_out_finalize(callid, fs_va);
     374}}}
     375
     376Note that the return value of ''async_share_out_finalize()'' is maybe unjustly ignored here. The kernel will attempt to create the mapping only after the server calls ''async_share_out_finalize()''.
    371377
    372378==== Sharing address space area in ====
     
    375381
    376382{{{
    377 #include <ipc/ipc.h>
    378 #include <async.h>
    379 ...
     383#include <async.h>
     384...
     385        async_exch_t *exch = async_exchange_begin(session);
     386        if (exch == NULL) {
     387                /* Handle error creating an exchange */
     388        }
     389
    380390        fs_reg_t *reg;
    381         int vfs_phone;
    382         int rc;
    383 ...
    384         rc = async_share_in_start_0_0(vfs_phone, reg->plb_ro, PLB_SIZE);
    385         if (rc != EOK) {
    386                 /* handle error */
    387         }
    388 
     391        int rc = async_share_in_start(exch, reg->plb_ro, PLB_SIZE);
     392        async_exchange_end(exch);
     393
     394        if (rc != EOK) {
     395                /* Error or the recipient denied the bid */
     396        }
    389397}}}
    390398
     
    392400
    393401{{{
    394 #include <ipc/ipc.h>
    395 #include <async.h>
    396 ...
    397         ipc_callid_t callid;
    398         size_t size;
    399 ...
    400         if (!async_share_in_receive(&callid, &size)) {
    401                 /* handle error */
    402         }
    403 }}}
    404 
    405 The server now has a chance to react to the request. If ''size'' does not meet the server's requirement, the server will reject the offer. Otherwise the server will accept it. Note that so far, the address space area flags were not specified. That will happen in the final phase:
    406 
    407 {{{
    408 ...
    409         uint8_t *plb;
    410         (void) async_share_in_finalize(callid, plb, AS_AREA_READ | AS_AREA_CACHEABLE);
    411 }}}
    412 
    413 Again, the kernel will not create the mapping before the server completes the final phase of the negotiation via ''ipc_share_in_finalize()''.
     402#include <async.h>
     403...
     404        ipc_callid_t callid;
     405        size_t size;
     406        if (!async_share_in_receive(&callid, &size)) {
     407                /* Protocol error - the sender is not requesting a share */
     408        }
     409
     410        /* Success, the receive phase is complete */
     411}}}
     412
     413The server now has a chance to react to the request. If ''size'' does not meet the server's requirements, the server will reject the offer. Otherwise the server will accept it. Note that so far, the address space area flags were not specified. That will happen in the final phase:
     414
     415{{{
     416        uint8_t *plb;
     417        (void) async_share_in_finalize(callid, plb, AS_AREA_READ | AS_AREA_CACHEABLE);
     418}}}
     419
     420Again, the kernel will not create the mapping before the server completes the final phase of the negotiation via ''async_share_in_finalize()''.