port.c (1425:3805a494e1ea) | port.c (1885:7bbaa5935f99) |
---|---|
1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the | 1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the |
5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. | 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. |
8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ | 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ |
21 |
|
22/* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27#pragma ident "%Z%%M% %I% %E% SMI" 28 29#include <sys/types.h> --- 605 unchanged lines hidden (view full) --- 635 /* user-defined events */ 636 error = port_send(pp, PORT_SOURCE_USER, (int)a1, (void *)a2); 637 break; 638 } 639 case PORT_DISPATCH: 640 { 641 /* 642 * library events, blocking | 22/* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27#pragma ident "%Z%%M% %I% %E% SMI" 28 29#include <sys/types.h> --- 605 unchanged lines hidden (view full) --- 635 /* user-defined events */ 636 error = port_send(pp, PORT_SOURCE_USER, (int)a1, (void *)a2); 637 break; 638 } 639 case PORT_DISPATCH: 640 { 641 /* 642 * library events, blocking |
643 * Only events of type PORT_SOURCE_AIO are currently allowed. | 643 * Only events of type PORT_SOURCE_AIO or PORT_SOURCE_MQ 644 * are currently allowed. |
644 */ | 645 */ |
645 if ((int)a1 != PORT_SOURCE_AIO) { | 646 if ((int)a1 != PORT_SOURCE_AIO && (int)a1 != PORT_SOURCE_MQ) { |
646 error = EINVAL; 647 break; 648 } 649 error = port_dispatch_event(pp, (int)opcode, (int)a1, (int)a2, 650 (uintptr_t)a3, (void *)a4); 651 break; 652 } 653 case PORT_DISSOCIATE: --- 216 unchanged lines hidden (view full) --- 870 871 pev->portkev_object = 0; 872 pev->portkev_events = events; 873 pev->portkev_user = user; 874 pev->portkev_callback = NULL; 875 pev->portkev_arg = NULL; 876 pev->portkev_flags = 0; 877 | 647 error = EINVAL; 648 break; 649 } 650 error = port_dispatch_event(pp, (int)opcode, (int)a1, (int)a2, 651 (uintptr_t)a3, (void *)a4); 652 break; 653 } 654 case PORT_DISSOCIATE: --- 216 unchanged lines hidden (view full) --- 871 872 pev->portkev_object = 0; 873 pev->portkev_events = events; 874 pev->portkev_user = user; 875 pev->portkev_callback = NULL; 876 pev->portkev_arg = NULL; 877 pev->portkev_flags = 0; 878 |
878 error = port_send_event(pev); 879 if (error) { 880 port_free_event_local(pev, 0); 881 return (error); 882 } | 879 port_send_event(pev); |
883 return (0); 884} 885 886/* 887 * The port_noshare() function returns 0 if the current event was generated 888 * by the same process. Otherwise is returns a value other than 0 and the 889 * event should not be delivered to the current processe. 890 * The port_noshare() function is normally used by the port_dispatch() --- 37 unchanged lines hidden (view full) --- 928 if (opcode & PORT_SYS_NOSHARE) { 929 pev->portkev_flags = PORT_KEV_NOSHARE; 930 pev->portkev_callback = port_noshare; 931 } else { 932 pev->portkev_flags = 0; 933 pev->portkev_callback = NULL; 934 } 935 | 880 return (0); 881} 882 883/* 884 * The port_noshare() function returns 0 if the current event was generated 885 * by the same process. Otherwise is returns a value other than 0 and the 886 * event should not be delivered to the current processe. 887 * The port_noshare() function is normally used by the port_dispatch() --- 37 unchanged lines hidden (view full) --- 925 if (opcode & PORT_SYS_NOSHARE) { 926 pev->portkev_flags = PORT_KEV_NOSHARE; 927 pev->portkev_callback = port_noshare; 928 } else { 929 pev->portkev_flags = 0; 930 pev->portkev_callback = NULL; 931 } 932 |
936 error = port_send_event(pev); 937 if (error) { 938 port_free_event_local(pev, 0); 939 return (error); 940 } | 933 port_send_event(pev); |
941 return (0); 942} 943 944 945/* 946 * The port_sendn() function is the kernel implementation of the event 947 * port API function port_sendn(3c). 948 * This function is able to send an event to a list of event ports. --- 57 unchanged lines hidden (view full) --- 1006 1007 pev->portkev_object = 0; 1008 pev->portkev_events = events; 1009 pev->portkev_user = user; 1010 pev->portkev_callback = NULL; 1011 pev->portkev_arg = NULL; 1012 pev->portkev_flags = 0; 1013 | 934 return (0); 935} 936 937 938/* 939 * The port_sendn() function is the kernel implementation of the event 940 * port API function port_sendn(3c). 941 * This function is able to send an event to a list of event ports. --- 57 unchanged lines hidden (view full) --- 999 1000 pev->portkev_object = 0; 1001 pev->portkev_events = events; 1002 pev->portkev_user = user; 1003 pev->portkev_callback = NULL; 1004 pev->portkev_arg = NULL; 1005 pev->portkev_flags = 0; 1006 |
1014 (void) port_send_event(pev); | 1007 port_send_event(pev); |
1015 releasef(port); 1016 } 1017 if (errorcnt) { 1018 error = EIO; 1019 if (copyout(elist, (void *)errors, nent * sizeof (int))) 1020 error = EFAULT; 1021 kmem_free(elist, nent * sizeof (int)); 1022 } --- 136 unchanged lines hidden (view full) --- 1159 1160 if (*nget > max && max > 0) 1161 return (EINVAL); 1162 1163 portq = &pp->port_queue; 1164 mutex_enter(&portq->portq_mutex); 1165 if (max == 0) { 1166 /* | 1008 releasef(port); 1009 } 1010 if (errorcnt) { 1011 error = EIO; 1012 if (copyout(elist, (void *)errors, nent * sizeof (int))) 1013 error = EFAULT; 1014 kmem_free(elist, nent * sizeof (int)); 1015 } --- 136 unchanged lines hidden (view full) --- 1152 1153 if (*nget > max && max > 0) 1154 return (EINVAL); 1155 1156 portq = &pp->port_queue; 1157 mutex_enter(&portq->portq_mutex); 1158 if (max == 0) { 1159 /* |
1167 * Return number of objects with events 1168 * The portq_block_mutex is required to synchronize this | 1160 * Return number of objects with events. 1161 * The port_block() call is required to synchronize this |
1169 * thread with another possible thread, which could be 1170 * retrieving events from the port queue. 1171 */ | 1162 * thread with another possible thread, which could be 1163 * retrieving events from the port queue. 1164 */ |
1172 mutex_enter(&portq->portq_block_mutex); | 1165 port_block(portq); |
1173 /* 1174 * Check if a second thread is currently retrieving events 1175 * and it is using the temporary event queue. 1176 */ 1177 if (portq->portq_tnent) { 1178 /* put remaining events back to the port queue */ 1179 port_push_eventq(portq); 1180 } 1181 *nget = portq->portq_nent; | 1166 /* 1167 * Check if a second thread is currently retrieving events 1168 * and it is using the temporary event queue. 1169 */ 1170 if (portq->portq_tnent) { 1171 /* put remaining events back to the port queue */ 1172 port_push_eventq(portq); 1173 } 1174 *nget = portq->portq_nent; |
1182 mutex_exit(&portq->portq_block_mutex); | 1175 port_unblock(portq); |
1183 mutex_exit(&portq->portq_mutex); 1184 return (0); 1185 } 1186 1187 if (uevp == NULL) { 1188 mutex_exit(&portq->portq_mutex); 1189 return (EFAULT); 1190 } --- 124 unchanged lines hidden (view full) --- 1315 (error == ETIME && flag))) { 1316 /* return without events */ 1317 port_check_return_cond(portq); 1318 mutex_exit(&portq->portq_mutex); 1319 return (error); 1320 } 1321 1322portnowait: | 1176 mutex_exit(&portq->portq_mutex); 1177 return (0); 1178 } 1179 1180 if (uevp == NULL) { 1181 mutex_exit(&portq->portq_mutex); 1182 return (EFAULT); 1183 } --- 124 unchanged lines hidden (view full) --- 1308 (error == ETIME && flag))) { 1309 /* return without events */ 1310 port_check_return_cond(portq); 1311 mutex_exit(&portq->portq_mutex); 1312 return (error); 1313 } 1314 1315portnowait: |
1323 nmax = max < portq->portq_nent ? max : portq->portq_nent; 1324 | |
1325 /* 1326 * Move port event queue to a temporary event queue . 1327 * New incoming events will be continue be posted to the event queue 1328 * and they will not be considered by the current thread. 1329 * The idea is to avoid lock contentions or an often locking/unlocking 1330 * of the port queue mutex. The contention and performance degradation 1331 * could happen because: 1332 * a) incoming events use the port queue mutex to enqueue new events and 1333 * b) before the event can be delivered to the application it is 1334 * necessary to notify the event sources about the event delivery. 1335 * Sometimes the event sources can require a long time to return and 1336 * the queue mutex would block incoming events. 1337 * During this time incoming events (port_send_event()) do not need 1338 * to awake threads waiting for events. Before the current thread 1339 * returns it will check the conditions to awake other waiting threads. 1340 */ 1341 portq->portq_getn++; /* number of threads retrieving events */ | 1316 /* 1317 * Move port event queue to a temporary event queue . 1318 * New incoming events will be continue be posted to the event queue 1319 * and they will not be considered by the current thread. 1320 * The idea is to avoid lock contentions or an often locking/unlocking 1321 * of the port queue mutex. The contention and performance degradation 1322 * could happen because: 1323 * a) incoming events use the port queue mutex to enqueue new events and 1324 * b) before the event can be delivered to the application it is 1325 * necessary to notify the event sources about the event delivery. 1326 * Sometimes the event sources can require a long time to return and 1327 * the queue mutex would block incoming events. 1328 * During this time incoming events (port_send_event()) do not need 1329 * to awake threads waiting for events. Before the current thread 1330 * returns it will check the conditions to awake other waiting threads. 1331 */ 1332 portq->portq_getn++; /* number of threads retrieving events */ |
1342 mutex_enter(&portq->portq_block_mutex); /* block other threads here */ | 1333 port_block(portq); /* block other threads here */ 1334 nmax = max < portq->portq_nent ? max : portq->portq_nent; 1335 |
1343 if (portq->portq_tnent) { 1344 /* 1345 * Move remaining events from previous thread back to the 1346 * port event queue. 1347 */ 1348 port_push_eventq(portq); 1349 } 1350 /* move port event queue to a temporary queue */ --- 87 unchanged lines hidden (view full) --- 1438 } 1439#endif /* _SYSCALL32_IMPL */ 1440 } 1441 1442 /* 1443 * Remember number of remaining events in the temporary event queue. 1444 */ 1445 portq->portq_tnent = tnent - nevents; | 1336 if (portq->portq_tnent) { 1337 /* 1338 * Move remaining events from previous thread back to the 1339 * port event queue. 1340 */ 1341 port_push_eventq(portq); 1342 } 1343 /* move port event queue to a temporary queue */ --- 87 unchanged lines hidden (view full) --- 1431 } 1432#endif /* _SYSCALL32_IMPL */ 1433 } 1434 1435 /* 1436 * Remember number of remaining events in the temporary event queue. 1437 */ 1438 portq->portq_tnent = tnent - nevents; |
1446 mutex_exit(&portq->portq_block_mutex); | |
1447 1448 /* 1449 * Work to do before return : 1450 * - push list of remaining events back to the top of the standard 1451 * port queue. 1452 * - if this is the last thread calling port_get(n) then wakeup the 1453 * thread waiting on close(2). 1454 * - check for a deferred cv_signal from port_send_event() and wakeup 1455 * the sleeping thread. 1456 */ 1457 1458 mutex_enter(&portq->portq_mutex); | 1439 1440 /* 1441 * Work to do before return : 1442 * - push list of remaining events back to the top of the standard 1443 * port queue. 1444 * - if this is the last thread calling port_get(n) then wakeup the 1445 * thread waiting on close(2). 1446 * - check for a deferred cv_signal from port_send_event() and wakeup 1447 * the sleeping thread. 1448 */ 1449 1450 mutex_enter(&portq->portq_mutex); |
1451 port_unblock(portq); |
|
1459 if (portq->portq_tnent) { 1460 /* 1461 * move remaining events in the temporary event queue back 1462 * to the port event queue 1463 */ 1464 port_push_eventq(portq); 1465 } 1466 portq->portq_getn--; /* update # of threads retrieving events */ --- 231 unchanged lines hidden (view full) --- 1698} 1699 1700/* 1701 * The port_get_kevent() function returns 1702 * - the event located at the head of the queue if 'last' pointer is NULL 1703 * - the next event after the event pointed by 'last' 1704 * The caller of this function is responsible for the integrity of the queue 1705 * in use: | 1452 if (portq->portq_tnent) { 1453 /* 1454 * move remaining events in the temporary event queue back 1455 * to the port event queue 1456 */ 1457 port_push_eventq(portq); 1458 } 1459 portq->portq_getn--; /* update # of threads retrieving events */ --- 231 unchanged lines hidden (view full) --- 1691} 1692 1693/* 1694 * The port_get_kevent() function returns 1695 * - the event located at the head of the queue if 'last' pointer is NULL 1696 * - the next event after the event pointed by 'last' 1697 * The caller of this function is responsible for the integrity of the queue 1698 * in use: |
1706 * - port_getn() is using a temporary queue protected with 1707 * portq->portq_block_mutex 1708 * - port_close_events() is working on the global event queue and protects the 1709 * queue with portq->portq_mutex. | 1699 * - port_getn() is using a temporary queue protected with port_block(). 1700 * - port_close_events() is working on the global event queue and protects 1701 * the queue with portq->portq_mutex. |
1710 */ | 1702 */ |
1711 | |
1712port_kevent_t * 1713port_get_kevent(list_t *list, port_kevent_t *last) 1714{ 1715 if (last == NULL) 1716 return (list_head(list)); 1717 else 1718 return (list_next(list, last)); 1719} --- 100 unchanged lines hidden (view full) --- 1820 * Take thread out of the queue. 1821 */ 1822static void 1823port_dequeue_thread(port_queue_t *portq, portget_t *pgetp) 1824{ 1825 if (pgetp->portget_next == pgetp) { 1826 /* last (single) waiting thread */ 1827 portq->portq_thread = NULL; | 1703port_kevent_t * 1704port_get_kevent(list_t *list, port_kevent_t *last) 1705{ 1706 if (last == NULL) 1707 return (list_head(list)); 1708 else 1709 return (list_next(list, last)); 1710} --- 100 unchanged lines hidden (view full) --- 1811 * Take thread out of the queue. 1812 */ 1813static void 1814port_dequeue_thread(port_queue_t *portq, portget_t *pgetp) 1815{ 1816 if (pgetp->portget_next == pgetp) { 1817 /* last (single) waiting thread */ 1818 portq->portq_thread = NULL; |
1819 portq->portq_nget = 0; |
|
1828 } else { 1829 pgetp->portget_prev->portget_next = pgetp->portget_next; 1830 pgetp->portget_next->portget_prev = pgetp->portget_prev; 1831 if (portq->portq_thread == pgetp) 1832 portq->portq_thread = pgetp->portget_next; 1833 portq->portq_nget = portq->portq_thread->portget_nget; 1834 } 1835 kmem_free(pgetp, sizeof (portget_t)); --- 19 unchanged lines hidden --- | 1820 } else { 1821 pgetp->portget_prev->portget_next = pgetp->portget_next; 1822 pgetp->portget_next->portget_prev = pgetp->portget_prev; 1823 if (portq->portq_thread == pgetp) 1824 portq->portq_thread = pgetp->portget_next; 1825 portq->portq_nget = portq->portq_thread->portget_nget; 1826 } 1827 kmem_free(pgetp, sizeof (portget_t)); --- 19 unchanged lines hidden --- |