159
171
/** Identifier of the incoming connection handled by the current fibril. */
160
fibril_local connection_t *FIBRIL_connection;
162
static void default_client_connection(ipc_callid_t callid, ipc_call_t *call);
163
static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call);
172
static fibril_local connection_t *FIBRIL_connection;
174
static void *default_client_data_constructor(void)
179
static void default_client_data_destructor(void *data)
183
static async_client_data_ctor_t async_client_data_create =
184
default_client_data_constructor;
185
static async_client_data_dtor_t async_client_data_destroy =
186
default_client_data_destructor;
188
void async_set_client_data_constructor(async_client_data_ctor_t ctor)
190
async_client_data_create = ctor;
193
void async_set_client_data_destructor(async_client_data_dtor_t dtor)
195
async_client_data_destroy = dtor;
198
void *async_client_data_get(void)
200
assert(FIBRIL_connection);
201
return FIBRIL_connection->client->data;
204
/** Default fibril function that gets called to handle new connection.
206
* This function is defined as a weak symbol - to be redefined in user code.
208
* @param callid Hash of the incoming call.
209
* @param call Data of the incoming call.
212
static void default_client_connection(ipc_callid_t callid, ipc_call_t *call)
214
ipc_answer_0(callid, ENOENT);
166
218
* Pointer to a fibril function that will be used to handle connections.
168
220
static async_client_conn_t client_connection = default_client_connection;
222
/** Default fibril function that gets called to handle interrupt notifications.
224
* This function is defined as a weak symbol - to be redefined in user code.
226
* @param callid Hash of the incoming call.
227
* @param call Data of the incoming call.
230
static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call)
171
235
* Pointer to a fibril function that will be used to handle interrupt
174
238
static async_client_conn_t interrupt_received = default_interrupt_received;
240
static hash_table_t client_hash_table;
176
241
static hash_table_t conn_hash_table;
177
242
static LIST_INITIALIZE(timeout_list);
179
#define CONN_HASH_TABLE_CHAINS 32
244
#define CLIENT_HASH_TABLE_BUCKETS 32
245
#define CONN_HASH_TABLE_BUCKETS 32
247
static hash_index_t client_hash(unsigned long key[])
250
return (((key[0]) >> 4) % CLIENT_HASH_TABLE_BUCKETS);
253
static int client_compare(unsigned long key[], hash_count_t keys, link_t *item)
255
client_t *client = hash_table_get_instance(item, client_t, link);
256
return (key[0] == client->in_task_hash);
259
static void client_remove(link_t *item)
263
/** Operations for the client hash table. */
264
static hash_table_operations_t client_hash_table_ops = {
266
.compare = client_compare,
267
.remove_callback = client_remove
181
270
/** Compute hash into the connection hash table based on the source phone hash.
480
541
static int connection_fibril(void *arg)
483
* Setup fibril-local connection pointer and call client_connection().
544
* Setup fibril-local connection pointer.
486
546
FIBRIL_connection = (connection_t *) arg;
548
futex_down(&async_futex);
551
* Add our reference for the current connection in the client task
552
* tracking structure. If this is the first reference, create and
553
* hash in a new tracking structure.
556
unsigned long key = FIBRIL_connection->in_task_hash;
557
link_t *lnk = hash_table_find(&client_hash_table, &key);
562
client = hash_table_get_instance(lnk, client_t, link);
565
client = malloc(sizeof(client_t));
567
ipc_answer_0(FIBRIL_connection->callid, ENOMEM);
568
futex_up(&async_futex);
572
client->in_task_hash = FIBRIL_connection->in_task_hash;
574
async_serialize_start();
575
client->data = async_client_data_create();
576
async_serialize_end();
579
hash_table_insert(&client_hash_table, &key, &client->link);
582
futex_up(&async_futex);
584
FIBRIL_connection->client = client;
587
* Call the connection handler function.
487
589
FIBRIL_connection->cfibril(FIBRIL_connection->callid,
488
590
&FIBRIL_connection->call);
490
/* Remove myself from the connection hash table */
491
futex_down(&async_futex);
492
unsigned long key = FIBRIL_connection->in_phone_hash;
593
* Remove the reference for this client task connection.
597
futex_down(&async_futex);
599
if (--client->refcnt == 0) {
600
hash_table_remove(&client_hash_table, &key, 1);
605
futex_up(&async_futex);
609
async_client_data_destroy(client->data);
615
* Remove myself from the connection hash table.
617
futex_down(&async_futex);
618
key = FIBRIL_connection->in_phone_hash;
493
619
hash_table_remove(&conn_hash_table, &key, 1);
494
620
futex_up(&async_futex);
496
/* Answer all remaining messages with EHANGUP */
623
* Answer all remaining messages with EHANGUP.
497
625
while (!list_empty(&FIBRIL_connection->msg_queue)) {
627
list_get_instance(FIBRIL_connection->msg_queue.next, msg_t,
500
msg = list_get_instance(FIBRIL_connection->msg_queue.next,
502
630
list_remove(&msg->link);
503
631
ipc_answer_0(msg->callid, EHANGUP);
636
* If the connection was hung-up, answer the last call,
637
* i.e. IPC_M_PHONE_HUNGUP.
507
639
if (FIBRIL_connection->close_callid)
508
640
ipc_answer_0(FIBRIL_connection->close_callid, EOK);
642
free(FIBRIL_connection);
1246
void async_msg_0(int phone, sysarg_t imethod)
1248
ipc_call_async_0(phone, imethod, NULL, NULL, true);
1251
void async_msg_1(int phone, sysarg_t imethod, sysarg_t arg1)
1253
ipc_call_async_1(phone, imethod, arg1, NULL, NULL, true);
1256
void async_msg_2(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2)
1258
ipc_call_async_2(phone, imethod, arg1, arg2, NULL, NULL, true);
1261
void async_msg_3(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2,
1264
ipc_call_async_3(phone, imethod, arg1, arg2, arg3, NULL, NULL, true);
1267
void async_msg_4(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2,
1268
sysarg_t arg3, sysarg_t arg4)
1270
ipc_call_async_4(phone, imethod, arg1, arg2, arg3, arg4, NULL, NULL,
1274
void async_msg_5(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2,
1275
sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
1277
ipc_call_async_5(phone, imethod, arg1, arg2, arg3, arg4, arg5, NULL,
1281
sysarg_t async_answer_0(ipc_callid_t callid, sysarg_t retval)
1283
return ipc_answer_0(callid, retval);
1286
sysarg_t async_answer_1(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1)
1288
return ipc_answer_1(callid, retval, arg1);
1291
sysarg_t async_answer_2(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1,
1294
return ipc_answer_2(callid, retval, arg1, arg2);
1297
sysarg_t async_answer_3(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1,
1298
sysarg_t arg2, sysarg_t arg3)
1300
return ipc_answer_3(callid, retval, arg1, arg2, arg3);
1303
sysarg_t async_answer_4(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1,
1304
sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
1306
return ipc_answer_4(callid, retval, arg1, arg2, arg3, arg4);
1309
sysarg_t async_answer_5(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1,
1310
sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
1312
return ipc_answer_5(callid, retval, arg1, arg2, arg3, arg4, arg5);
1315
int async_forward_fast(ipc_callid_t callid, int phoneid, sysarg_t imethod,
1316
sysarg_t arg1, sysarg_t arg2, unsigned int mode)
1318
return ipc_forward_fast(callid, phoneid, imethod, arg1, arg2, mode);
1321
int async_forward_slow(ipc_callid_t callid, int phoneid, sysarg_t imethod,
1322
sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
1325
return ipc_forward_slow(callid, phoneid, imethod, arg1, arg2, arg3, arg4,
1329
/** Wrapper for making IPC_M_CONNECT_TO_ME calls using the async framework.
1331
* Ask through phone for a new connection to some service.
1333
* @param phone Phone handle used for contacting the other side.
1334
* @param arg1 User defined argument.
1335
* @param arg2 User defined argument.
1336
* @param arg3 User defined argument.
1337
* @param client_receiver Connection handing routine.
1339
* @return New phone handle on success or a negative error code.
1342
int async_connect_to_me(int phone, sysarg_t arg1, sysarg_t arg2,
1343
sysarg_t arg3, async_client_conn_t client_receiver)
1346
sysarg_t phone_hash;
1347
int rc = async_req_3_5(phone, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
1348
NULL, NULL, NULL, &task_hash, &phone_hash);
1352
if (client_receiver != NULL)
1353
async_new_connection(task_hash, phone_hash, 0, NULL,
1103
1359
/** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
1105
1361
* Ask through phone for a new connection to some service.
1107
* @param phoneid Phone handle used for contacting the other side.
1108
* @param arg1 User defined argument.
1109
* @param arg2 User defined argument.
1110
* @param arg3 User defined argument.
1112
* @return New phone handle on success or a negative error code.
1363
* @param phone Phone handle used for contacting the other side.
1364
* @param arg1 User defined argument.
1365
* @param arg2 User defined argument.
1366
* @param arg3 User defined argument.
1368
* @return New phone handle on success or a negative error code.
1115
async_connect_me_to(int phoneid, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3)
1371
int async_connect_me_to(int phone, sysarg_t arg1, sysarg_t arg2,
1118
1374
sysarg_t newphid;
1120
rc = async_req_3_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3, NULL,
1121
NULL, NULL, NULL, &newphid);
1375
int rc = async_req_3_5(phone, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
1376
NULL, NULL, NULL, NULL, &newphid);
1126
1381
return newphid;
1129
1384
/** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
1131
1386
* Ask through phone for a new connection to some service and block until
1134
* @param phoneid Phone handle used for contacting the other side.
1135
* @param arg1 User defined argument.
1136
* @param arg2 User defined argument.
1137
* @param arg3 User defined argument.
1139
* @return New phone handle on success or a negative error code.
1389
* @param phoneid Phone handle used for contacting the other side.
1390
* @param arg1 User defined argument.
1391
* @param arg2 User defined argument.
1392
* @param arg3 User defined argument.
1394
* @return New phone handle on success or a negative error code.
1142
async_connect_me_to_blocking(int phoneid, sysarg_t arg1, sysarg_t arg2,
1397
int async_connect_me_to_blocking(int phoneid, sysarg_t arg1, sysarg_t arg2,
1146
1400
sysarg_t newphid;
1148
rc = async_req_4_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
1401
int rc = async_req_4_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
1149
1402
IPC_FLAG_BLOCKING, NULL, NULL, NULL, NULL, &newphid);
1154
1407
return newphid;
1157
/** Wrapper for making IPC_M_SHARE_IN calls using the async framework.
1159
* @param phoneid Phone that will be used to contact the receiving side.
1160
* @param dst Destination address space area base.
1161
* @param size Size of the destination address space area.
1162
* @param arg User defined argument.
1163
* @param flags Storage where the received flags will be stored. Can be
1166
* @return Zero on success or a negative error code from errno.h.
1410
/** Connect to a task specified by id.
1413
int async_connect_kbox(task_id_t id)
1415
return ipc_connect_kbox(id);
1418
/** Wrapper for ipc_hangup.
1420
* @param phone Phone handle to hung up.
1422
* @return Zero on success or a negative error code.
1425
int async_hangup(int phone)
1427
return ipc_hangup(phone);
1430
/** Interrupt one thread of this task from waiting for IPC. */
1431
void async_poke(void)
1436
/** Wrapper for IPC_M_SHARE_IN calls using the async framework.
1438
* @param phoneid Phone that will be used to contact the receiving side.
1439
* @param dst Destination address space area base.
1440
* @param size Size of the destination address space area.
1441
* @param arg User defined argument.
1442
* @param flags Storage for the received flags. Can be NULL.
1444
* @return Zero on success or a negative error code from errno.h.
1168
1447
int async_share_in_start(int phoneid, void *dst, size_t size, sysarg_t arg,
1448
unsigned int *flags)
1172
1450
sysarg_t tmp_flags;
1173
res = async_req_3_2(phoneid, IPC_M_SHARE_IN, (sysarg_t) dst,
1451
int res = async_req_3_2(phoneid, IPC_M_SHARE_IN, (sysarg_t) dst,
1174
1452
(sysarg_t) size, arg, NULL, &tmp_flags);
1455
*flags = (unsigned int) tmp_flags;
1180
1460
/** Wrapper for receiving the IPC_M_SHARE_IN calls using the async framework.
1182
* This wrapper only makes it more comfortable to receive IPC_M_SHARE_IN calls
1183
* so that the user doesn't have to remember the meaning of each IPC argument.
1462
* This wrapper only makes it more comfortable to receive IPC_M_SHARE_IN
1463
* calls so that the user doesn't have to remember the meaning of each IPC
1185
1466
* So far, this wrapper is to be used from within a connection fibril.
1187
* @param callid Storage where the hash of the IPC_M_SHARE_IN call will
1189
* @param size Destination address space area size.
1191
* @return Non-zero on success, zero on failure.
1468
* @param callid Storage for the hash of the IPC_M_SHARE_IN call.
1469
* @param size Destination address space area size.
1471
* @return True on success, false on failure.
1193
int async_share_in_receive(ipc_callid_t *callid, size_t *size)
1474
bool async_share_in_receive(ipc_callid_t *callid, size_t *size)
1197
1476
assert(callid);
1200
1480
*callid = async_get_call(&data);
1201
1482
if (IPC_GET_IMETHOD(data) != IPC_M_SHARE_IN)
1203
1485
*size = (size_t) IPC_GET_ARG2(data);
1207
1489
/** Wrapper for answering the IPC_M_SHARE_IN calls using the async framework.
1209
* This wrapper only makes it more comfortable to answer IPC_M_DATA_READ calls
1210
* so that the user doesn't have to remember the meaning of each IPC argument.
1212
* @param callid Hash of the IPC_M_DATA_READ call to answer.
1213
* @param src Source address space base.
1214
* @param flags Flags to be used for sharing. Bits can be only cleared.
1216
* @return Zero on success or a value from @ref errno.h on failure.
1491
* This wrapper only makes it more comfortable to answer IPC_M_DATA_READ
1492
* calls so that the user doesn't have to remember the meaning of each IPC
1495
* @param callid Hash of the IPC_M_DATA_READ call to answer.
1496
* @param src Source address space base.
1497
* @param flags Flags to be used for sharing. Bits can be only cleared.
1499
* @return Zero on success or a value from @ref errno.h on failure.
1218
int async_share_in_finalize(ipc_callid_t callid, void *src, int flags)
1502
int async_share_in_finalize(ipc_callid_t callid, void *src, unsigned int flags)
1220
1504
return ipc_share_in_finalize(callid, src, flags);
1223
/** Wrapper for making IPC_M_SHARE_OUT calls using the async framework.
1225
* @param phoneid Phone that will be used to contact the receiving side.
1226
* @param src Source address space area base address.
1227
* @param flags Flags to be used for sharing. Bits can be only cleared.
1229
* @return Zero on success or a negative error code from errno.h.
1507
/** Wrapper for IPC_M_SHARE_OUT calls using the async framework.
1509
* @param phoneid Phone that will be used to contact the receiving side.
1510
* @param src Source address space area base address.
1511
* @param flags Flags to be used for sharing. Bits can be only cleared.
1513
* @return Zero on success or a negative error code from errno.h.
1231
int async_share_out_start(int phoneid, void *src, int flags)
1516
int async_share_out_start(int phoneid, void *src, unsigned int flags)
1233
1518
return async_req_3_0(phoneid, IPC_M_SHARE_OUT, (sysarg_t) src, 0,
1234
1519
(sysarg_t) flags);
1237
1522
/** Wrapper for receiving the IPC_M_SHARE_OUT calls using the async framework.
1239
* This wrapper only makes it more comfortable to receive IPC_M_SHARE_OUT calls
1240
* so that the user doesn't have to remember the meaning of each IPC argument.
1524
* This wrapper only makes it more comfortable to receive IPC_M_SHARE_OUT
1525
* calls so that the user doesn't have to remember the meaning of each IPC
1242
1528
* So far, this wrapper is to be used from within a connection fibril.
1244
* @param callid Storage where the hash of the IPC_M_SHARE_OUT call will
1246
* @param size Storage where the source address space area size will be
1248
* @param flags Storage where the sharing flags will be stored.
1250
* @return Non-zero on success, zero on failure.
1530
* @param callid Storage for the hash of the IPC_M_SHARE_OUT call.
1531
* @param size Storage for the source address space area size.
1532
* @param flags Storage for the sharing flags.
1534
* @return True on success, false on failure.
1252
int async_share_out_receive(ipc_callid_t *callid, size_t *size, int *flags)
1537
bool async_share_out_receive(ipc_callid_t *callid, size_t *size, unsigned int *flags)
1256
1539
assert(callid);
1260
1544
*callid = async_get_call(&data);
1261
1546
if (IPC_GET_IMETHOD(data) != IPC_M_SHARE_OUT)
1263
1549
*size = (size_t) IPC_GET_ARG2(data);
1264
*flags = (int) IPC_GET_ARG3(data);
1550
*flags = (unsigned int) IPC_GET_ARG3(data);
1268
1554
/** Wrapper for answering the IPC_M_SHARE_OUT calls using the async framework.
1270
* This wrapper only makes it more comfortable to answer IPC_M_SHARE_OUT calls
1271
* so that the user doesn't have to remember the meaning of each IPC argument.
1273
* @param callid Hash of the IPC_M_DATA_WRITE call to answer.
1274
* @param dst Destination address space area base address.
1276
* @return Zero on success or a value from @ref errno.h on failure.
1556
* This wrapper only makes it more comfortable to answer IPC_M_SHARE_OUT
1557
* calls so that the user doesn't have to remember the meaning of each IPC
1560
* @param callid Hash of the IPC_M_DATA_WRITE call to answer.
1561
* @param dst Destination address space area base address.
1563
* @return Zero on success or a value from @ref errno.h on failure.
1278
1566
int async_share_out_finalize(ipc_callid_t callid, void *dst)
1280
1568
return ipc_share_out_finalize(callid, dst);
1284
/** Wrapper for making IPC_M_DATA_READ calls using the async framework.
1286
* @param phoneid Phone that will be used to contact the receiving side.
1287
* @param dst Address of the beginning of the destination buffer.
1288
* @param size Size of the destination buffer.
1290
* @return Zero on success or a negative error code from errno.h.
1571
/** Wrapper for IPC_M_DATA_READ calls using the async framework.
1573
* @param phoneid Phone that will be used to contact the receiving side.
1574
* @param dst Address of the beginning of the destination buffer.
1575
* @param size Size of the destination buffer.
1576
* @param flags Flags to control the data transfer.
1578
* @return Zero on success or a negative error code from errno.h.
1292
int async_data_read_start(int phoneid, void *dst, size_t size)
1582
async_data_read_start_generic(int phoneid, void *dst, size_t size, int flags)
1294
return async_req_2_0(phoneid, IPC_M_DATA_READ, (sysarg_t) dst,
1584
return async_req_3_0(phoneid, IPC_M_DATA_READ, (sysarg_t) dst,
1585
(sysarg_t) size, (sysarg_t) flags);
1298
1588
/** Wrapper for receiving the IPC_M_DATA_READ calls using the async framework.
1300
* This wrapper only makes it more comfortable to receive IPC_M_DATA_READ calls
1301
* so that the user doesn't have to remember the meaning of each IPC argument.
1590
* This wrapper only makes it more comfortable to receive IPC_M_DATA_READ
1591
* calls so that the user doesn't have to remember the meaning of each IPC
1303
1594
* So far, this wrapper is to be used from within a connection fibril.
1305
* @param callid Storage where the hash of the IPC_M_DATA_READ call will
1307
* @param size Storage where the maximum size will be stored. Can be
1310
* @return Non-zero on success, zero on failure.
1596
* @param callid Storage for the hash of the IPC_M_DATA_READ.
1597
* @param size Storage for the maximum size. Can be NULL.
1599
* @return True on success, false on failure.
1312
int async_data_read_receive(ipc_callid_t *callid, size_t *size)
1602
bool async_data_read_receive(ipc_callid_t *callid, size_t *size)
1314
1606
ipc_call_t data;
1318
1607
*callid = async_get_call(&data);
1319
1609
if (IPC_GET_IMETHOD(data) != IPC_M_DATA_READ)
1322
1613
*size = (size_t) IPC_GET_ARG2(data);
1326
1618
/** Wrapper for answering the IPC_M_DATA_READ calls using the async framework.
1328
* This wrapper only makes it more comfortable to answer IPC_M_DATA_READ calls
1329
* so that the user doesn't have to remember the meaning of each IPC argument.
1331
* @param callid Hash of the IPC_M_DATA_READ call to answer.
1332
* @param src Source address for the IPC_M_DATA_READ call.
1333
* @param size Size for the IPC_M_DATA_READ call. Can be smaller than
1334
* the maximum size announced by the sender.
1336
* @return Zero on success or a value from @ref errno.h on failure.
1620
* This wrapper only makes it more comfortable to answer IPC_M_DATA_READ
1621
* calls so that the user doesn't have to remember the meaning of each IPC
1624
* @param callid Hash of the IPC_M_DATA_READ call to answer.
1625
* @param src Source address for the IPC_M_DATA_READ call.
1626
* @param size Size for the IPC_M_DATA_READ call. Can be smaller than
1627
* the maximum size announced by the sender.
1629
* @return Zero on success or a value from @ref errno.h on failure.
1338
1632
int async_data_read_finalize(ipc_callid_t callid, const void *src, size_t size)