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 ---