Changes in uspace/lib/c/generic/async.c [6a5d05b:4d6629f] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/async.c
r6a5d05b r4d6629f 77 77 * } 78 78 * 79 * port_handler(ic handle, *icall)79 * port_handler(icallid, *icall) 80 80 * { 81 81 * if (want_refuse) { 82 * async_answer_0(ic handle, ELIMIT);82 * async_answer_0(icallid, ELIMIT); 83 83 * return; 84 84 * } 85 * async_answer_0(ic handle, EOK);86 * 87 * c handle= async_get_call(&call);88 * somehow_handle_the_call(c handle, call);89 * async_answer_2(c handle, 1, 2, 3);90 * 91 * c handle= async_get_call(&call);85 * async_answer_0(icallid, EOK); 86 * 87 * callid = async_get_call(&call); 88 * somehow_handle_the_call(callid, call); 89 * async_answer_2(callid, 1, 2, 3); 90 * 91 * callid = async_get_call(&call); 92 92 * ... 93 93 * } … … 106 106 #include <fibril.h> 107 107 #include <adt/hash_table.h> 108 #include <adt/hash.h>109 108 #include <adt/list.h> 110 109 #include <assert.h> … … 113 112 #include <libarch/barrier.h> 114 113 #include <stdbool.h> 115 #include < stdlib.h>114 #include <malloc.h> 116 115 #include <mem.h> 117 116 #include <stdlib.h> … … 185 184 link_t link; 186 185 187 cap_handle_t chandle;186 ipc_callid_t callid; 188 187 ipc_call_t call; 189 188 } msg_t; … … 205 204 ipc_call_t *dataptr; 206 205 207 int retval;206 sysarg_t retval; 208 207 } amsg_t; 209 208 … … 237 236 238 237 /** Identification of the opening call. */ 239 cap_handle_t chandle;238 ipc_callid_t callid; 240 239 241 240 /** Call data of the opening call. */ … … 243 242 244 243 /** Identification of the closing call. */ 245 cap_handle_t close_chandle;244 ipc_callid_t close_callid; 246 245 247 246 /** Fibril function that will be used to handle the connection. */ … … 332 331 msg->destroyed = false; 333 332 msg->dataptr = NULL; 334 msg->retval = EINVAL;333 msg->retval = (sysarg_t) EINVAL; 335 334 awaiter_initialize(&msg->wdata); 336 335 } … … 374 373 /** Default fallback fibril function. 375 374 * 376 * This fallback fibril function gets called on incomming connections that do377 * not have a specific handler defined.378 * 379 * @param c handle Handleof the incoming call.380 * @param call 381 * @param arg 382 * 383 */ 384 static void default_fallback_port_handler( cap_handle_t chandle,385 ipc_call_t *call,void *arg)386 { 387 ipc_answer_0(c handle, ENOENT);375 * This fallback fibril function gets called on incomming 376 * connections that do not have a specific handler defined. 377 * 378 * @param callid Hash of the incoming call. 379 * @param call Data of the incoming call. 380 * @param arg Local argument 381 * 382 */ 383 static void default_fallback_port_handler(ipc_callid_t callid, ipc_call_t *call, 384 void *arg) 385 { 386 ipc_answer_0(callid, ENOENT); 388 387 } 389 388 … … 588 587 }; 589 588 590 typedef struct { 591 task_id_t task_id; 592 sysarg_t phone_hash; 593 } conn_key_t; 594 595 /** Compute hash into the connection hash table 596 * 597 * The hash is based on the source task ID and the source phone hash. The task 598 * ID is included in the hash because a phone hash alone might not be unique 599 * while we still track connections for killed tasks due to kernel's recycling 600 * of phone structures. 601 * 602 * @param key Pointer to the connection key structure. 589 /** Compute hash into the connection hash table based on the source phone hash. 590 * 591 * @param key Pointer to source phone hash. 603 592 * 604 593 * @return Index into the connection hash table. … … 607 596 static size_t conn_key_hash(void *key) 608 597 { 609 conn_key_t *ck = (conn_key_t *) key; 610 611 size_t hash = 0; 612 hash = hash_combine(hash, LOWER32(ck->task_id)); 613 hash = hash_combine(hash, UPPER32(ck->task_id)); 614 hash = hash_combine(hash, ck->phone_hash); 615 return hash; 598 sysarg_t in_phone_hash = *(sysarg_t *) key; 599 return in_phone_hash; 616 600 } 617 601 … … 619 603 { 620 604 connection_t *conn = hash_table_get_inst(item, connection_t, link); 621 return conn_key_hash(&(conn_key_t){ 622 .task_id = conn->in_task_id, 623 .phone_hash = conn->in_phone_hash 624 }); 605 return conn_key_hash(&conn->in_phone_hash); 625 606 } 626 607 627 608 static bool conn_key_equal(void *key, const ht_link_t *item) 628 609 { 629 conn_key_t *ck = (conn_key_t *) key;610 sysarg_t in_phone_hash = *(sysarg_t *) key; 630 611 connection_t *conn = hash_table_get_inst(item, connection_t, link); 631 return ((ck->task_id == conn->in_task_id) && 632 (ck->phone_hash == conn->in_phone_hash)); 612 return (in_phone_hash == conn->in_phone_hash); 633 613 } 634 614 … … 715 695 client_t *client = async_client_get(fibril_connection->in_task_id, true); 716 696 if (!client) { 717 ipc_answer_0(fibril_connection->c handle, ENOMEM);697 ipc_answer_0(fibril_connection->callid, ENOMEM); 718 698 return 0; 719 699 } … … 724 704 * Call the connection handler function. 725 705 */ 726 fibril_connection->handler(fibril_connection->c handle,706 fibril_connection->handler(fibril_connection->callid, 727 707 &fibril_connection->call, fibril_connection->data); 728 708 … … 736 716 */ 737 717 futex_down(&async_futex); 738 hash_table_remove(&conn_hash_table, &(conn_key_t){ 739 .task_id = fibril_connection->in_task_id, 740 .phone_hash = fibril_connection->in_phone_hash 741 }); 718 hash_table_remove(&conn_hash_table, &fibril_connection->in_phone_hash); 742 719 futex_up(&async_futex); 743 720 … … 751 728 752 729 list_remove(&msg->link); 753 ipc_answer_0(msg->c handle, EHANGUP);730 ipc_answer_0(msg->callid, EHANGUP); 754 731 free(msg); 755 732 } … … 759 736 * i.e. IPC_M_PHONE_HUNGUP. 760 737 */ 761 if (fibril_connection->close_c handle)762 ipc_answer_0(fibril_connection->close_c handle, EOK);738 if (fibril_connection->close_callid) 739 ipc_answer_0(fibril_connection->close_callid, EOK); 763 740 764 741 free(fibril_connection); 765 return EOK;742 return 0; 766 743 } 767 744 768 745 /** Create a new fibril for a new connection. 769 746 * 770 * Create new fibril for connection, fill in connection structures and insert it771 * into the hash table, so that later we can easily do routing of messages to772 * particular fibrils.773 * 774 * @param in_task_id 775 * @param in_phone_hash 776 * @param c handle Handleof the opening IPC_M_CONNECT_ME_TO call.777 * If chandle is CAP_NIL, the connection was opened by778 * 779 * 780 * @param call 781 * @param handler 782 * @param data 783 * 784 * @return 747 * Create new fibril for connection, fill in connection structures 748 * and insert it into the hash table, so that later we can easily 749 * do routing of messages to particular fibrils. 750 * 751 * @param in_task_id Identification of the incoming connection. 752 * @param in_phone_hash Identification of the incoming connection. 753 * @param callid Hash of the opening IPC_M_CONNECT_ME_TO call. 754 * If callid is zero, the connection was opened by 755 * accepting the IPC_M_CONNECT_TO_ME call and this 756 * function is called directly by the server. 757 * @param call Call data of the opening call. 758 * @param handler Connection handler. 759 * @param data Client argument to pass to the connection handler. 760 * 761 * @return New fibril id or NULL on failure. 785 762 * 786 763 */ 787 764 static fid_t async_new_connection(task_id_t in_task_id, sysarg_t in_phone_hash, 788 cap_handle_t chandle, ipc_call_t *call, async_port_handler_t handler,765 ipc_callid_t callid, ipc_call_t *call, async_port_handler_t handler, 789 766 void *data) 790 767 { 791 768 connection_t *conn = malloc(sizeof(*conn)); 792 769 if (!conn) { 793 if (c handle != CAP_NIL)794 ipc_answer_0(c handle, ENOMEM);770 if (callid) 771 ipc_answer_0(callid, ENOMEM); 795 772 796 773 return (uintptr_t) NULL; … … 800 777 conn->in_phone_hash = in_phone_hash; 801 778 list_initialize(&conn->msg_queue); 802 conn->c handle = chandle;803 conn->close_c handle = CAP_NIL;779 conn->callid = callid; 780 conn->close_callid = 0; 804 781 conn->handler = handler; 805 782 conn->data = data; … … 815 792 free(conn); 816 793 817 if (c handle != CAP_NIL)818 ipc_answer_0(c handle, ENOMEM);794 if (callid) 795 ipc_answer_0(callid, ENOMEM); 819 796 820 797 return (uintptr_t) NULL; … … 844 821 * @param port_id ID of the newly created port. 845 822 * 846 * @return Zero on success or a nerror code.823 * @return Zero on success or a negative error code. 847 824 * 848 825 */ … … 860 837 &answer); 861 838 862 int ret;839 sysarg_t ret; 863 840 async_wait_for(req, &ret); 864 841 if (ret != EOK) … … 892 869 893 870 fid_t fid = async_new_connection(answer.in_task_id, phone_hash, 894 CAP_NIL, NULL, handler, data);871 0, NULL, handler, data); 895 872 if (fid == (uintptr_t) NULL) 896 873 return ENOMEM; … … 961 938 * timeouts are unregistered. 962 939 * 963 * @param c handle Handleof the incoming call.964 * @param call 940 * @param callid Hash of the incoming call. 941 * @param call Data of the incoming call. 965 942 * 966 943 * @return False if the call doesn't match any connection. … … 968 945 * 969 946 */ 970 static bool route_call( cap_handle_t chandle, ipc_call_t *call)947 static bool route_call(ipc_callid_t callid, ipc_call_t *call) 971 948 { 972 949 assert(call); … … 974 951 futex_down(&async_futex); 975 952 976 ht_link_t *link = hash_table_find(&conn_hash_table, &(conn_key_t){ 977 .task_id = call->in_task_id, 978 .phone_hash = call->in_phone_hash 979 }); 953 ht_link_t *link = hash_table_find(&conn_hash_table, &call->in_phone_hash); 980 954 if (!link) { 981 955 futex_up(&async_futex); … … 991 965 } 992 966 993 msg->c handle = chandle;967 msg->callid = callid; 994 968 msg->call = *call; 995 969 list_append(&msg->link, &conn->msg_queue); 996 970 997 971 if (IPC_GET_IMETHOD(*call) == IPC_M_PHONE_HUNGUP) 998 conn->close_c handle = chandle;972 conn->close_callid = callid; 999 973 1000 974 /* If the connection fibril is waiting for an event, activate it */ … … 1017 991 /** Process notification. 1018 992 * 993 * @param callid Hash of the incoming call. 1019 994 * @param call Data of the incoming call. 1020 995 * 1021 996 */ 1022 static void process_notification(ipc_call _t *call)997 static void process_notification(ipc_callid_t callid, ipc_call_t *call) 1023 998 { 1024 999 async_notification_handler_t handler = NULL; … … 1041 1016 1042 1017 if (handler) 1043 handler(call , data);1018 handler(callid, call, data); 1044 1019 } 1045 1020 … … 1051 1026 * @param ucode Top-half pseudocode handler. 1052 1027 * 1053 * @param[out] handle IRQ capability handle on success. 1054 * 1055 * @return An error code. 1028 * @return IRQ capability handle on success. 1029 * @return Negative error code. 1056 1030 * 1057 1031 */ 1058 1032 int async_irq_subscribe(int inr, async_notification_handler_t handler, 1059 void *data, const irq_code_t *ucode , cap_handle_t *handle)1033 void *data, const irq_code_t *ucode) 1060 1034 { 1061 1035 notification_t *notification = … … 1077 1051 futex_up(&async_futex); 1078 1052 1079 cap_handle_t cap; 1080 int rc = ipc_irq_subscribe(inr, imethod, ucode, &cap); 1081 if (rc == EOK && handle != NULL) { 1082 *handle = cap; 1083 } 1084 return rc; 1053 return ipc_irq_subscribe(inr, imethod, ucode); 1085 1054 } 1086 1055 … … 1089 1058 * @param cap IRQ capability handle. 1090 1059 * 1091 * @return Zero on success or a nerror code.1060 * @return Zero on success or a negative error code. 1092 1061 * 1093 1062 */ … … 1106 1075 * @param data Notification handler client data. 1107 1076 * 1108 * @return Zero on success or a nerror code.1077 * @return Zero on success or a negative error code. 1109 1078 * 1110 1079 */ … … 1139 1108 * @param data Notification handler client data. 1140 1109 * 1141 * @return Zero on success or a nerror code.1110 * @return Zero on success or a negative error code. 1142 1111 * 1143 1112 */ … … 1192 1161 /** Return new incoming message for the current (fibril-local) connection. 1193 1162 * 1194 * @param call Storage where the incoming call data will be stored. 1195 * @param usecs Timeout in microseconds. Zero denotes no timeout. 1196 * 1197 * @return If no timeout was specified, then a handle of the incoming call is 1198 * returned. If a timeout is specified, then a handle of the incoming 1199 * call is returned unless the timeout expires prior to receiving a 1200 * message. In that case zero CAP_NIL is returned. 1201 */ 1202 cap_handle_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs) 1163 * @param call Storage where the incoming call data will be stored. 1164 * @param usecs Timeout in microseconds. Zero denotes no timeout. 1165 * 1166 * @return If no timeout was specified, then a hash of the 1167 * incoming call is returned. If a timeout is specified, 1168 * then a hash of the incoming call is returned unless 1169 * the timeout expires prior to receiving a message. In 1170 * that case zero is returned. 1171 * 1172 */ 1173 ipc_callid_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs) 1203 1174 { 1204 1175 assert(call); … … 1223 1194 /* If nothing in queue, wait until something arrives */ 1224 1195 while (list_empty(&conn->msg_queue)) { 1225 if (conn->close_c handle) {1196 if (conn->close_callid) { 1226 1197 /* 1227 1198 * Handle the case when the connection was already … … 1234 1205 IPC_SET_IMETHOD(*call, IPC_M_PHONE_HUNGUP); 1235 1206 futex_up(&async_futex); 1236 return conn->close_c handle;1207 return conn->close_callid; 1237 1208 } 1238 1209 … … 1259 1230 /* If we timed out -> exit */ 1260 1231 futex_up(&async_futex); 1261 return CAP_NIL;1232 return 0; 1262 1233 } 1263 1234 } … … 1267 1238 list_remove(&msg->link); 1268 1239 1269 cap_handle_t chandle = msg->chandle;1240 ipc_callid_t callid = msg->callid; 1270 1241 *call = msg->call; 1271 1242 free(msg); 1272 1243 1273 1244 futex_up(&async_futex); 1274 return c handle;1245 return callid; 1275 1246 } 1276 1247 … … 1335 1306 * Otherwise the call is routed to its connection fibril. 1336 1307 * 1337 * @param c handle Handleof the incoming call.1338 * @param call 1339 * 1340 */ 1341 static void handle_call( cap_handle_t chandle, ipc_call_t *call)1308 * @param callid Hash of the incoming call. 1309 * @param call Data of the incoming call. 1310 * 1311 */ 1312 static void handle_call(ipc_callid_t callid, ipc_call_t *call) 1342 1313 { 1343 1314 assert(call); 1344 1315 1345 1316 /* Kernel notification */ 1346 if ((c handle == CAP_NIL) && (call->flags & IPC_CALL_NOTIF)) {1317 if ((callid & IPC_CALLID_NOTIFICATION)) { 1347 1318 fibril_t *fibril = (fibril_t *) __tcb_get()->fibril_data; 1348 1319 unsigned oldsw = fibril->switches; 1349 1320 1350 process_notification(call );1321 process_notification(callid, call); 1351 1322 1352 1323 if (oldsw != fibril->switches) { … … 1374 1345 sysarg_t in_phone_hash = IPC_GET_ARG5(*call); 1375 1346 1376 async_ port_handler_t handler = fallback_port_handler;1347 async_notification_handler_t handler = fallback_port_handler; 1377 1348 void *data = fallback_port_data; 1378 1349 … … 1384 1355 } 1385 1356 1386 async_new_connection(call->in_task_id, in_phone_hash, c handle,1357 async_new_connection(call->in_task_id, in_phone_hash, callid, 1387 1358 call, handler, data); 1388 1359 return; … … 1390 1361 1391 1362 /* Try to route the call through the connection hash table */ 1392 if (route_call(c handle, call))1363 if (route_call(callid, call)) 1393 1364 return; 1394 1365 1395 1366 /* Unknown call from unknown phone - hang it up */ 1396 ipc_answer_0(c handle, EHANGUP);1367 ipc_answer_0(callid, EHANGUP); 1397 1368 } 1398 1369 … … 1489 1460 1490 1461 ipc_call_t call; 1491 i nt rc= ipc_wait_cycle(&call, timeout, flags);1462 ipc_callid_t callid = ipc_wait_cycle(&call, timeout, flags); 1492 1463 1493 1464 atomic_dec(&threads_in_ipc_wait); 1494 1465 1495 assert(rc == EOK); 1496 1497 if (call.cap_handle == CAP_NIL) { 1498 if ((call.flags & 1499 (IPC_CALL_NOTIF | IPC_CALL_ANSWERED)) == 0) { 1500 /* Neither a notification nor an answer. */ 1501 handle_expired_timeouts(); 1502 continue; 1503 } 1466 if (!callid) { 1467 handle_expired_timeouts(); 1468 continue; 1504 1469 } 1505 1506 if (call .flags & IPC_CALL_ANSWERED)1470 1471 if (callid & IPC_CALLID_ANSWERED) 1507 1472 continue; 1508 1509 handle_call(call .cap_handle, &call);1510 } 1511 1473 1474 handle_call(callid, &call); 1475 } 1476 1512 1477 return 0; 1513 1478 } … … 1640 1605 * @param arg3 Service-defined payload argument. 1641 1606 * @param arg4 Service-defined payload argument. 1642 * @param dataptr If non-NULL, storage where the reply data will be stored. 1607 * @param dataptr If non-NULL, storage where the reply data will be 1608 * stored. 1643 1609 * 1644 1610 * @return Hash of the sent message or 0 on error. … … 1709 1675 * 1710 1676 */ 1711 void async_wait_for(aid_t amsgid, int *retval)1677 void async_wait_for(aid_t amsgid, sysarg_t *retval) 1712 1678 { 1713 1679 assert(amsgid); … … 1755 1721 * 1756 1722 */ 1757 int async_wait_timeout(aid_t amsgid, int *retval, suseconds_t timeout)1723 int async_wait_timeout(aid_t amsgid, sysarg_t *retval, suseconds_t timeout) 1758 1724 { 1759 1725 assert(amsgid); … … 1856 1822 void async_usleep(suseconds_t timeout) 1857 1823 { 1858 awaiter_t awaiter; 1859 awaiter_initialize(&awaiter); 1860 1861 awaiter.fid = fibril_get_id(); 1862 1863 getuptime(&awaiter.to_event.expires); 1864 tv_add_diff(&awaiter.to_event.expires, timeout); 1824 amsg_t *msg = amsg_create(); 1825 if (!msg) 1826 return; 1827 1828 msg->wdata.fid = fibril_get_id(); 1829 1830 getuptime(&msg->wdata.to_event.expires); 1831 tv_add_diff(&msg->wdata.to_event.expires, timeout); 1865 1832 1866 1833 futex_down(&async_futex); 1867 1834 1868 async_insert_timeout(& awaiter);1835 async_insert_timeout(&msg->wdata); 1869 1836 1870 1837 /* Leave the async_futex locked when entering this function */ … … 1872 1839 1873 1840 /* Futex is up automatically after fibril_switch() */ 1874 } 1875 1876 /** Delay execution for the specified number of seconds 1877 * 1878 * @param sec Number of seconds to sleep 1879 */ 1880 void async_sleep(unsigned int sec) 1881 { 1882 /* 1883 * Sleep in 1000 second steps to support 1884 * full argument range 1885 */ 1886 1887 while (sec > 0) { 1888 unsigned int period = (sec > 1000) ? 1000 : sec; 1889 1890 async_usleep(period * 1000000); 1891 sec -= period; 1892 } 1841 1842 amsg_destroy(msg); 1893 1843 } 1894 1844 … … 1912 1862 * @param r5 If non-NULL, storage for the 5th reply argument. 1913 1863 * 1914 * @return Return code of the reply or a nerror code.1915 * 1916 */ 1917 int async_req_fast(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,1864 * @return Return code of the reply or a negative error code. 1865 * 1866 */ 1867 sysarg_t async_req_fast(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1, 1918 1868 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t *r1, sysarg_t *r2, 1919 1869 sysarg_t *r3, sysarg_t *r4, sysarg_t *r5) … … 1926 1876 &result); 1927 1877 1928 int rc;1878 sysarg_t rc; 1929 1879 async_wait_for(aid, &rc); 1930 1880 … … 1964 1914 * @param r5 If non-NULL, storage for the 5th reply argument. 1965 1915 * 1966 * @return Return code of the reply or a nerror code.1967 * 1968 */ 1969 int async_req_slow(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,1916 * @return Return code of the reply or a negative error code. 1917 * 1918 */ 1919 sysarg_t async_req_slow(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1, 1970 1920 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, sysarg_t *r1, 1971 1921 sysarg_t *r2, sysarg_t *r3, sysarg_t *r4, sysarg_t *r5) … … 1978 1928 &result); 1979 1929 1980 int rc;1930 sysarg_t rc; 1981 1931 async_wait_for(aid, &rc); 1982 1932 … … 2042 1992 } 2043 1993 2044 int async_answer_0(cap_handle_t chandle, int retval)2045 { 2046 return ipc_answer_0(c handle, retval);2047 } 2048 2049 int async_answer_1(cap_handle_t chandle, int retval, sysarg_t arg1)2050 { 2051 return ipc_answer_1(c handle, retval, arg1);2052 } 2053 2054 int async_answer_2(cap_handle_t chandle, int retval, sysarg_t arg1,1994 sysarg_t async_answer_0(ipc_callid_t callid, sysarg_t retval) 1995 { 1996 return ipc_answer_0(callid, retval); 1997 } 1998 1999 sysarg_t async_answer_1(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1) 2000 { 2001 return ipc_answer_1(callid, retval, arg1); 2002 } 2003 2004 sysarg_t async_answer_2(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1, 2055 2005 sysarg_t arg2) 2056 2006 { 2057 return ipc_answer_2(c handle, retval, arg1, arg2);2058 } 2059 2060 int async_answer_3(cap_handle_t chandle, int retval, sysarg_t arg1,2007 return ipc_answer_2(callid, retval, arg1, arg2); 2008 } 2009 2010 sysarg_t async_answer_3(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1, 2061 2011 sysarg_t arg2, sysarg_t arg3) 2062 2012 { 2063 return ipc_answer_3(c handle, retval, arg1, arg2, arg3);2064 } 2065 2066 int async_answer_4(cap_handle_t chandle, int retval, sysarg_t arg1,2013 return ipc_answer_3(callid, retval, arg1, arg2, arg3); 2014 } 2015 2016 sysarg_t async_answer_4(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1, 2067 2017 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4) 2068 2018 { 2069 return ipc_answer_4(c handle, retval, arg1, arg2, arg3, arg4);2070 } 2071 2072 int async_answer_5(cap_handle_t chandle, int retval, sysarg_t arg1,2019 return ipc_answer_4(callid, retval, arg1, arg2, arg3, arg4); 2020 } 2021 2022 sysarg_t async_answer_5(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1, 2073 2023 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5) 2074 2024 { 2075 return ipc_answer_5(c handle, retval, arg1, arg2, arg3, arg4, arg5);2076 } 2077 2078 int async_forward_fast( cap_handle_t chandle, async_exch_t *exch,2025 return ipc_answer_5(callid, retval, arg1, arg2, arg3, arg4, arg5); 2026 } 2027 2028 int async_forward_fast(ipc_callid_t callid, async_exch_t *exch, 2079 2029 sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, unsigned int mode) 2080 2030 { … … 2082 2032 return ENOENT; 2083 2033 2084 return ipc_forward_fast(c handle, exch->phone, imethod, arg1, arg2, mode);2085 } 2086 2087 int async_forward_slow( cap_handle_t chandle, async_exch_t *exch,2034 return ipc_forward_fast(callid, exch->phone, imethod, arg1, arg2, mode); 2035 } 2036 2037 int async_forward_slow(ipc_callid_t callid, async_exch_t *exch, 2088 2038 sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, 2089 2039 sysarg_t arg4, sysarg_t arg5, unsigned int mode) … … 2092 2042 return ENOENT; 2093 2043 2094 return ipc_forward_slow(c handle, exch->phone, imethod, arg1, arg2, arg3,2044 return ipc_forward_slow(callid, exch->phone, imethod, arg1, arg2, arg3, 2095 2045 arg4, arg5, mode); 2096 2046 } … … 2105 2055 * @param arg3 User defined argument. 2106 2056 * 2107 * @return Zero on success or a nerror code.2057 * @return Zero on success or a negative error code. 2108 2058 * 2109 2059 */ … … 2118 2068 &answer); 2119 2069 2120 int rc;2070 sysarg_t rc; 2121 2071 async_wait_for(req, &rc); 2122 2072 if (rc != EOK) … … 2127 2077 2128 2078 static int async_connect_me_to_internal(int phone, sysarg_t arg1, sysarg_t arg2, 2129 sysarg_t arg3, sysarg_t arg4 , int *out_phone)2079 sysarg_t arg3, sysarg_t arg4) 2130 2080 { 2131 2081 ipc_call_t result; 2132 2133 // XXX: Workaround for GCC's inability to infer association between2134 // rc == EOK and *out_phone being assigned.2135 *out_phone = -1;2136 2082 2137 2083 amsg_t *msg = amsg_create(); … … 2145 2091 msg, reply_received); 2146 2092 2147 int rc;2093 sysarg_t rc; 2148 2094 async_wait_for((aid_t) msg, &rc); 2149 2095 … … 2151 2097 return rc; 2152 2098 2153 *out_phone = (int) IPC_GET_ARG5(result); 2154 return EOK; 2099 return (int) IPC_GET_ARG5(result); 2155 2100 } 2156 2101 … … 2182 2127 } 2183 2128 2184 int phone; 2185 int rc = async_connect_me_to_internal(exch->phone, arg1, arg2, arg3, 2186 0, &phone); 2187 if (rc != EOK) { 2188 errno = rc; 2129 int phone = async_connect_me_to_internal(exch->phone, arg1, arg2, arg3, 2130 0); 2131 if (phone < 0) { 2132 errno = phone; 2189 2133 free(sess); 2190 2134 return NULL; … … 2235 2179 } 2236 2180 2237 int phone; 2238 int rc = async_connect_me_to_internal(exch->phone, iface, arg2, 2239 arg3, 0, &phone); 2240 if (rc != EOK) { 2241 errno = rc; 2181 int phone = async_connect_me_to_internal(exch->phone, iface, arg2, 2182 arg3, 0); 2183 if (phone < 0) { 2184 errno = phone; 2242 2185 free(sess); 2243 2186 return NULL; … … 2306 2249 } 2307 2250 2308 int phone; 2309 int rc = async_connect_me_to_internal(exch->phone, arg1, arg2, arg3, 2310 IPC_FLAG_BLOCKING, &phone); 2311 2312 if (rc != EOK) { 2313 errno = rc; 2251 int phone = async_connect_me_to_internal(exch->phone, arg1, arg2, arg3, 2252 IPC_FLAG_BLOCKING); 2253 2254 if (phone < 0) { 2255 errno = phone; 2314 2256 free(sess); 2315 2257 return NULL; … … 2360 2302 } 2361 2303 2362 int phone; 2363 int rc = async_connect_me_to_internal(exch->phone, iface, arg2, 2364 arg3, IPC_FLAG_BLOCKING, &phone); 2365 if (rc != EOK) { 2366 errno = rc; 2304 int phone = async_connect_me_to_internal(exch->phone, iface, arg2, 2305 arg3, IPC_FLAG_BLOCKING); 2306 if (phone < 0) { 2307 errno = phone; 2367 2308 free(sess); 2368 2309 return NULL; … … 2396 2337 } 2397 2338 2398 cap_handle_t phone; 2399 int rc = ipc_connect_kbox(id, &phone); 2400 if (rc != EOK) { 2401 errno = rc; 2339 int phone = ipc_connect_kbox(id); 2340 if (phone < 0) { 2341 errno = phone; 2402 2342 free(sess); 2403 2343 return NULL; … … 2430 2370 * @param sess Session to hung up. 2431 2371 * 2432 * @return Zero on success or a nerror code.2372 * @return Zero on success or a negative error code. 2433 2373 * 2434 2374 */ … … 2516 2456 } else if (mgmt == EXCHANGE_PARALLEL) { 2517 2457 int phone; 2518 int rc;2519 2458 2520 2459 retry: … … 2522 2461 * Make a one-time attempt to connect a new data phone. 2523 2462 */ 2524 rc= async_connect_me_to_internal(sess->phone, sess->arg1,2525 sess->arg2, sess->arg3, 0 , &phone);2526 if ( rc == EOK) {2463 phone = async_connect_me_to_internal(sess->phone, sess->arg1, 2464 sess->arg2, sess->arg3, 0); 2465 if (phone >= 0) { 2527 2466 exch = (async_exch_t *) malloc(sizeof(async_exch_t)); 2528 2467 if (exch != NULL) { … … 2610 2549 * base address. Cannot be NULL. 2611 2550 * 2612 * @return Zero on success or a nerror code from errno.h.2551 * @return Zero on success or a negative error code from errno.h. 2613 2552 * 2614 2553 */ … … 2639 2578 * So far, this wrapper is to be used from within a connection fibril. 2640 2579 * 2641 * @param c handle Storage for the handleof the IPC_M_SHARE_IN call.2642 * @param size 2580 * @param callid Storage for the hash of the IPC_M_SHARE_IN call. 2581 * @param size Destination address space area size. 2643 2582 * 2644 2583 * @return True on success, false on failure. 2645 2584 * 2646 2585 */ 2647 bool async_share_in_receive( cap_handle_t *chandle, size_t *size)2648 { 2649 assert(c handle);2586 bool async_share_in_receive(ipc_callid_t *callid, size_t *size) 2587 { 2588 assert(callid); 2650 2589 assert(size); 2651 2590 2652 2591 ipc_call_t data; 2653 *c handle= async_get_call(&data);2592 *callid = async_get_call(&data); 2654 2593 2655 2594 if (IPC_GET_IMETHOD(data) != IPC_M_SHARE_IN) … … 2666 2605 * argument. 2667 2606 * 2668 * @param c handle Handleof the IPC_M_DATA_READ call to answer.2669 * @param src 2670 * @param flags 2607 * @param callid Hash of the IPC_M_DATA_READ call to answer. 2608 * @param src Source address space base. 2609 * @param flags Flags to be used for sharing. Bits can be only cleared. 2671 2610 * 2672 2611 * @return Zero on success or a value from @ref errno.h on failure. 2673 2612 * 2674 2613 */ 2675 int async_share_in_finalize( cap_handle_t chandle, void *src, unsigned int flags)2676 { 2677 return ipc_answer_3(c handle, EOK, (sysarg_t) src, (sysarg_t) flags,2614 int async_share_in_finalize(ipc_callid_t callid, void *src, unsigned int flags) 2615 { 2616 return ipc_answer_3(callid, EOK, (sysarg_t) src, (sysarg_t) flags, 2678 2617 (sysarg_t) __entry); 2679 2618 } … … 2685 2624 * @param flags Flags to be used for sharing. Bits can be only cleared. 2686 2625 * 2687 * @return Zero on success or a nerror code from errno.h.2626 * @return Zero on success or a negative error code from errno.h. 2688 2627 * 2689 2628 */ … … 2705 2644 * So far, this wrapper is to be used from within a connection fibril. 2706 2645 * 2707 * @param c handleStorage for the hash of the IPC_M_SHARE_OUT call.2708 * @param size 2709 * @param flags 2646 * @param callid Storage for the hash of the IPC_M_SHARE_OUT call. 2647 * @param size Storage for the source address space area size. 2648 * @param flags Storage for the sharing flags. 2710 2649 * 2711 2650 * @return True on success, false on failure. 2712 2651 * 2713 2652 */ 2714 bool async_share_out_receive(cap_handle_t *chandle, size_t *size, 2715 unsigned int *flags) 2716 { 2717 assert(chandle); 2653 bool async_share_out_receive(ipc_callid_t *callid, size_t *size, unsigned int *flags) 2654 { 2655 assert(callid); 2718 2656 assert(size); 2719 2657 assert(flags); 2720 2658 2721 2659 ipc_call_t data; 2722 *c handle= async_get_call(&data);2660 *callid = async_get_call(&data); 2723 2661 2724 2662 if (IPC_GET_IMETHOD(data) != IPC_M_SHARE_OUT) … … 2736 2674 * argument. 2737 2675 * 2738 * @param c handle Handleof the IPC_M_DATA_WRITE call to answer.2739 * @param dst 2740 * 2741 * 2742 * @return 2743 * 2744 */ 2745 int async_share_out_finalize( cap_handle_t chandle, void **dst)2746 { 2747 return ipc_answer_2(c handle, EOK, (sysarg_t) __entry, (sysarg_t) dst);2676 * @param callid Hash of the IPC_M_DATA_WRITE call to answer. 2677 * @param dst Address of the storage for the destination address space area 2678 * base address. 2679 * 2680 * @return Zero on success or a value from @ref errno.h on failure. 2681 * 2682 */ 2683 int async_share_out_finalize(ipc_callid_t callid, void **dst) 2684 { 2685 return ipc_answer_2(callid, EOK, (sysarg_t) __entry, (sysarg_t) dst); 2748 2686 } 2749 2687 … … 2771 2709 * @param size Size of the destination buffer. 2772 2710 * 2773 * @return Zero on success or a nerror code from errno.h.2711 * @return Zero on success or a negative error code from errno.h. 2774 2712 * 2775 2713 */ … … 2791 2729 * So far, this wrapper is to be used from within a connection fibril. 2792 2730 * 2793 * @param c handle Storage for the handleof the IPC_M_DATA_READ.2794 * @param size 2731 * @param callid Storage for the hash of the IPC_M_DATA_READ. 2732 * @param size Storage for the maximum size. Can be NULL. 2795 2733 * 2796 2734 * @return True on success, false on failure. 2797 2735 * 2798 2736 */ 2799 bool async_data_read_receive( cap_handle_t *chandle, size_t *size)2737 bool async_data_read_receive(ipc_callid_t *callid, size_t *size) 2800 2738 { 2801 2739 ipc_call_t data; 2802 return async_data_read_receive_call(c handle, &data, size);2740 return async_data_read_receive_call(callid, &data, size); 2803 2741 } 2804 2742 … … 2811 2749 * So far, this wrapper is to be used from within a connection fibril. 2812 2750 * 2813 * @param c handle Storage for the handleof the IPC_M_DATA_READ.2814 * @param size 2751 * @param callid Storage for the hash of the IPC_M_DATA_READ. 2752 * @param size Storage for the maximum size. Can be NULL. 2815 2753 * 2816 2754 * @return True on success, false on failure. 2817 2755 * 2818 2756 */ 2819 bool async_data_read_receive_call( cap_handle_t *chandle, ipc_call_t *data,2757 bool async_data_read_receive_call(ipc_callid_t *callid, ipc_call_t *data, 2820 2758 size_t *size) 2821 2759 { 2822 assert(c handle);2760 assert(callid); 2823 2761 assert(data); 2824 2762 2825 *c handle= async_get_call(data);2763 *callid = async_get_call(data); 2826 2764 2827 2765 if (IPC_GET_IMETHOD(*data) != IPC_M_DATA_READ) … … 2840 2778 * argument. 2841 2779 * 2842 * @param c handle Handleof the IPC_M_DATA_READ call to answer.2843 * @param src 2844 * @param size 2845 * 2846 * 2847 * @return 2848 * 2849 */ 2850 int async_data_read_finalize( cap_handle_t chandle, const void *src, size_t size)2851 { 2852 return ipc_answer_2(c handle, EOK, (sysarg_t) src, (sysarg_t) size);2780 * @param callid Hash of the IPC_M_DATA_READ call to answer. 2781 * @param src Source address for the IPC_M_DATA_READ call. 2782 * @param size Size for the IPC_M_DATA_READ call. Can be smaller than 2783 * the maximum size announced by the sender. 2784 * 2785 * @return Zero on success or a value from @ref errno.h on failure. 2786 * 2787 */ 2788 int async_data_read_finalize(ipc_callid_t callid, const void *src, size_t size) 2789 { 2790 return ipc_answer_2(callid, EOK, (sysarg_t) src, (sysarg_t) size); 2853 2791 } 2854 2792 … … 2863 2801 return ENOENT; 2864 2802 2865 cap_handle_t chandle;2866 if (!async_data_read_receive(&c handle, NULL)) {2867 ipc_answer_0(c handle, EINVAL);2803 ipc_callid_t callid; 2804 if (!async_data_read_receive(&callid, NULL)) { 2805 ipc_answer_0(callid, EINVAL); 2868 2806 return EINVAL; 2869 2807 } … … 2872 2810 dataptr); 2873 2811 if (msg == 0) { 2874 ipc_answer_0(c handle, EINVAL);2812 ipc_answer_0(callid, EINVAL); 2875 2813 return EINVAL; 2876 2814 } 2877 2815 2878 int retval = ipc_forward_fast(c handle, exch->phone, 0, 0, 0,2816 int retval = ipc_forward_fast(callid, exch->phone, 0, 0, 0, 2879 2817 IPC_FF_ROUTE_FROM_ME); 2880 2818 if (retval != EOK) { 2881 2819 async_forget(msg); 2882 ipc_answer_0(c handle, retval);2820 ipc_answer_0(callid, retval); 2883 2821 return retval; 2884 2822 } 2885 2823 2886 int rc;2824 sysarg_t rc; 2887 2825 async_wait_for(msg, &rc); 2888 2826 … … 2896 2834 * @param size Size of the source buffer. 2897 2835 * 2898 * @return Zero on success or a nerror code from errno.h.2836 * @return Zero on success or a negative error code from errno.h. 2899 2837 * 2900 2838 */ … … 2916 2854 * So far, this wrapper is to be used from within a connection fibril. 2917 2855 * 2918 * @param c handle Storage for the handleof the IPC_M_DATA_WRITE.2919 * @param size 2920 * 2921 * @return 2922 * 2923 */ 2924 bool async_data_write_receive( cap_handle_t *chandle, size_t *size)2856 * @param callid Storage for the hash of the IPC_M_DATA_WRITE. 2857 * @param size Storage for the suggested size. May be NULL. 2858 * 2859 * @return True on success, false on failure. 2860 * 2861 */ 2862 bool async_data_write_receive(ipc_callid_t *callid, size_t *size) 2925 2863 { 2926 2864 ipc_call_t data; 2927 return async_data_write_receive_call(c handle, &data, size);2865 return async_data_write_receive_call(callid, &data, size); 2928 2866 } 2929 2867 … … 2936 2874 * So far, this wrapper is to be used from within a connection fibril. 2937 2875 * 2938 * @param c handle Storage for the handleof the IPC_M_DATA_WRITE.2939 * @param data 2940 * @param size 2876 * @param callid Storage for the hash of the IPC_M_DATA_WRITE. 2877 * @param data Storage for the ipc call data. 2878 * @param size Storage for the suggested size. May be NULL. 2941 2879 * 2942 2880 * @return True on success, false on failure. 2943 2881 * 2944 2882 */ 2945 bool async_data_write_receive_call( cap_handle_t *chandle, ipc_call_t *data,2883 bool async_data_write_receive_call(ipc_callid_t *callid, ipc_call_t *data, 2946 2884 size_t *size) 2947 2885 { 2948 assert(c handle);2886 assert(callid); 2949 2887 assert(data); 2950 2888 2951 *c handle= async_get_call(data);2889 *callid = async_get_call(data); 2952 2890 2953 2891 if (IPC_GET_IMETHOD(*data) != IPC_M_DATA_WRITE) … … 2966 2904 * argument. 2967 2905 * 2968 * @param c handle Handleof the IPC_M_DATA_WRITE call to answer.2969 * @param dst 2970 * @param size 2971 * 2972 * @return 2973 * 2974 */ 2975 int async_data_write_finalize( cap_handle_t chandle, void *dst, size_t size)2976 { 2977 return ipc_answer_2(c handle, EOK, (sysarg_t) dst, (sysarg_t) size);2906 * @param callid Hash of the IPC_M_DATA_WRITE call to answer. 2907 * @param dst Final destination address for the IPC_M_DATA_WRITE call. 2908 * @param size Final size for the IPC_M_DATA_WRITE call. 2909 * 2910 * @return Zero on success or a value from @ref errno.h on failure. 2911 * 2912 */ 2913 int async_data_write_finalize(ipc_callid_t callid, void *dst, size_t size) 2914 { 2915 return ipc_answer_2(callid, EOK, (sysarg_t) dst, (sysarg_t) size); 2978 2916 } 2979 2917 … … 3005 2943 assert(data); 3006 2944 3007 cap_handle_t chandle;2945 ipc_callid_t callid; 3008 2946 size_t size; 3009 if (!async_data_write_receive(&c handle, &size)) {3010 ipc_answer_0(c handle, EINVAL);2947 if (!async_data_write_receive(&callid, &size)) { 2948 ipc_answer_0(callid, EINVAL); 3011 2949 return EINVAL; 3012 2950 } 3013 2951 3014 2952 if (size < min_size) { 3015 ipc_answer_0(c handle, EINVAL);2953 ipc_answer_0(callid, EINVAL); 3016 2954 return EINVAL; 3017 2955 } 3018 2956 3019 2957 if ((max_size > 0) && (size > max_size)) { 3020 ipc_answer_0(c handle, EINVAL);2958 ipc_answer_0(callid, EINVAL); 3021 2959 return EINVAL; 3022 2960 } 3023 2961 3024 2962 if ((granularity > 0) && ((size % granularity) != 0)) { 3025 ipc_answer_0(c handle, EINVAL);2963 ipc_answer_0(callid, EINVAL); 3026 2964 return EINVAL; 3027 2965 } … … 3035 2973 3036 2974 if (arg_data == NULL) { 3037 ipc_answer_0(c handle, ENOMEM);2975 ipc_answer_0(callid, ENOMEM); 3038 2976 return ENOMEM; 3039 2977 } 3040 2978 3041 int rc = async_data_write_finalize(c handle, arg_data, size);2979 int rc = async_data_write_finalize(callid, arg_data, size); 3042 2980 if (rc != EOK) { 3043 2981 free(arg_data); … … 3062 3000 * 3063 3001 */ 3064 void async_data_write_void( int retval)3065 { 3066 cap_handle_t chandle;3067 async_data_write_receive(&c handle, NULL);3068 ipc_answer_0(c handle, retval);3002 void async_data_write_void(sysarg_t retval) 3003 { 3004 ipc_callid_t callid; 3005 async_data_write_receive(&callid, NULL); 3006 ipc_answer_0(callid, retval); 3069 3007 } 3070 3008 … … 3079 3017 return ENOENT; 3080 3018 3081 cap_handle_t chandle;3082 if (!async_data_write_receive(&c handle, NULL)) {3083 ipc_answer_0(c handle, EINVAL);3019 ipc_callid_t callid; 3020 if (!async_data_write_receive(&callid, NULL)) { 3021 ipc_answer_0(callid, EINVAL); 3084 3022 return EINVAL; 3085 3023 } … … 3088 3026 dataptr); 3089 3027 if (msg == 0) { 3090 ipc_answer_0(c handle, EINVAL);3028 ipc_answer_0(callid, EINVAL); 3091 3029 return EINVAL; 3092 3030 } 3093 3031 3094 int retval = ipc_forward_fast(c handle, exch->phone, 0, 0, 0,3032 int retval = ipc_forward_fast(callid, exch->phone, 0, 0, 0, 3095 3033 IPC_FF_ROUTE_FROM_ME); 3096 3034 if (retval != EOK) { 3097 3035 async_forget(msg); 3098 ipc_answer_0(c handle, retval);3036 ipc_answer_0(callid, retval); 3099 3037 return retval; 3100 3038 } 3101 3039 3102 int rc;3040 sysarg_t rc; 3103 3041 async_wait_for(msg, &rc); 3104 3042 … … 3121 3059 /* Accept the phone */ 3122 3060 ipc_call_t call; 3123 cap_handle_t chandle = async_get_call(&call); 3124 cap_handle_t phandle = (cap_handle_t) IPC_GET_ARG5(call); 3125 3126 if ((IPC_GET_IMETHOD(call) != IPC_M_CONNECT_TO_ME) || (phandle < 0)) { 3127 async_answer_0(chandle, EINVAL); 3061 ipc_callid_t callid = async_get_call(&call); 3062 int phone = (int) IPC_GET_ARG5(call); 3063 3064 if ((IPC_GET_IMETHOD(call) != IPC_M_CONNECT_TO_ME) || 3065 (phone < 0)) { 3066 async_answer_0(callid, EINVAL); 3128 3067 return NULL; 3129 3068 } … … 3131 3070 async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t)); 3132 3071 if (sess == NULL) { 3133 async_answer_0(c handle, ENOMEM);3072 async_answer_0(callid, ENOMEM); 3134 3073 return NULL; 3135 3074 } … … 3137 3076 sess->iface = 0; 3138 3077 sess->mgmt = mgmt; 3139 sess->phone = ph andle;3078 sess->phone = phone; 3140 3079 sess->arg1 = 0; 3141 3080 sess->arg2 = 0; … … 3150 3089 3151 3090 /* Acknowledge the connected phone */ 3152 async_answer_0(c handle, EOK);3091 async_answer_0(callid, EOK); 3153 3092 3154 3093 return sess; … … 3171 3110 async_sess_t *async_callback_receive_start(exch_mgmt_t mgmt, ipc_call_t *call) 3172 3111 { 3173 cap_handle_t phandle = (cap_handle_t) IPC_GET_ARG5(*call); 3174 3175 if ((IPC_GET_IMETHOD(*call) != IPC_M_CONNECT_TO_ME) || (phandle < 0)) 3112 int phone = (int) IPC_GET_ARG5(*call); 3113 3114 if ((IPC_GET_IMETHOD(*call) != IPC_M_CONNECT_TO_ME) || 3115 (phone < 0)) 3176 3116 return NULL; 3177 3117 … … 3182 3122 sess->iface = 0; 3183 3123 sess->mgmt = mgmt; 3184 sess->phone = ph andle;3124 sess->phone = phone; 3185 3125 sess->arg1 = 0; 3186 3126 sess->arg2 = 0; … … 3204 3144 } 3205 3145 3206 bool async_state_change_receive( cap_handle_t *chandle, sysarg_t *arg1,3146 bool async_state_change_receive(ipc_callid_t *callid, sysarg_t *arg1, 3207 3147 sysarg_t *arg2, sysarg_t *arg3) 3208 3148 { 3209 assert(c handle);3149 assert(callid); 3210 3150 3211 3151 ipc_call_t call; 3212 *c handle= async_get_call(&call);3152 *callid = async_get_call(&call); 3213 3153 3214 3154 if (IPC_GET_IMETHOD(call) != IPC_M_STATE_CHANGE_AUTHORIZE) … … 3225 3165 } 3226 3166 3227 int async_state_change_finalize( cap_handle_t chandle, async_exch_t *other_exch)3228 { 3229 return ipc_answer_1(c handle, EOK, other_exch->phone);3167 int async_state_change_finalize(ipc_callid_t callid, async_exch_t *other_exch) 3168 { 3169 return ipc_answer_1(callid, EOK, other_exch->phone); 3230 3170 } 3231 3171
Note:
See TracChangeset
for help on using the changeset viewer.