10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*6247Sraf * Common Development and Distribution License (the "License"). 6*6247Sraf * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 21*6247Sraf 220Sstevel@tonic-gate /* 23*6247Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include "lint.h" 300Sstevel@tonic-gate #include "thr_uberdata.h" 310Sstevel@tonic-gate 320Sstevel@tonic-gate static uint32_t _semvaluemax; 330Sstevel@tonic-gate 340Sstevel@tonic-gate /* 350Sstevel@tonic-gate * Check to see if anyone is waiting for this semaphore. 360Sstevel@tonic-gate */ 370Sstevel@tonic-gate #pragma weak sema_held = _sema_held 380Sstevel@tonic-gate int 390Sstevel@tonic-gate _sema_held(sema_t *sp) 400Sstevel@tonic-gate { 410Sstevel@tonic-gate return (sp->count == 0); 420Sstevel@tonic-gate } 430Sstevel@tonic-gate 440Sstevel@tonic-gate #pragma weak sema_init = _sema_init 450Sstevel@tonic-gate /* ARGSUSED2 */ 460Sstevel@tonic-gate int 470Sstevel@tonic-gate _sema_init(sema_t *sp, unsigned int count, int type, void *arg) 480Sstevel@tonic-gate { 490Sstevel@tonic-gate if (_semvaluemax == 0) 500Sstevel@tonic-gate _semvaluemax = (uint32_t)_sysconf(_SC_SEM_VALUE_MAX); 510Sstevel@tonic-gate if ((type != USYNC_THREAD && type != USYNC_PROCESS) || 520Sstevel@tonic-gate (count > _semvaluemax)) 530Sstevel@tonic-gate return (EINVAL); 540Sstevel@tonic-gate (void) _memset(sp, 0, sizeof (*sp)); 550Sstevel@tonic-gate sp->count = count; 560Sstevel@tonic-gate sp->type = (uint16_t)type; 570Sstevel@tonic-gate sp->magic = SEMA_MAGIC; 580Sstevel@tonic-gate return (0); 590Sstevel@tonic-gate } 600Sstevel@tonic-gate 610Sstevel@tonic-gate #pragma weak sema_destroy = _sema_destroy 620Sstevel@tonic-gate int 630Sstevel@tonic-gate _sema_destroy(sema_t *sp) 640Sstevel@tonic-gate { 650Sstevel@tonic-gate sp->magic = 0; 660Sstevel@tonic-gate tdb_sync_obj_deregister(sp); 670Sstevel@tonic-gate return (0); 680Sstevel@tonic-gate } 690Sstevel@tonic-gate 700Sstevel@tonic-gate static int 710Sstevel@tonic-gate sema_wait_impl(sema_t *sp, timespec_t *tsp) 720Sstevel@tonic-gate { 730Sstevel@tonic-gate lwp_sema_t *lsp = (lwp_sema_t *)sp; 740Sstevel@tonic-gate ulwp_t *self = curthread; 750Sstevel@tonic-gate uberdata_t *udp = self->ul_uberdata; 760Sstevel@tonic-gate tdb_sema_stats_t *ssp = SEMA_STATS(sp, udp); 770Sstevel@tonic-gate hrtime_t begin_sleep = 0; 780Sstevel@tonic-gate uint_t count; 790Sstevel@tonic-gate int error = 0; 800Sstevel@tonic-gate 810Sstevel@tonic-gate /* 820Sstevel@tonic-gate * All variations of sema_wait() are cancellation points. 830Sstevel@tonic-gate */ 840Sstevel@tonic-gate _cancelon(); 850Sstevel@tonic-gate 860Sstevel@tonic-gate if (ssp) 870Sstevel@tonic-gate tdb_incr(ssp->sema_wait); 880Sstevel@tonic-gate 890Sstevel@tonic-gate self->ul_sp = stkptr(); 900Sstevel@tonic-gate self->ul_wchan = lsp; 910Sstevel@tonic-gate if (__td_event_report(self, TD_SLEEP, udp)) { 920Sstevel@tonic-gate self->ul_td_evbuf.eventnum = TD_SLEEP; 930Sstevel@tonic-gate self->ul_td_evbuf.eventdata = lsp; 940Sstevel@tonic-gate tdb_event(TD_SLEEP, udp); 950Sstevel@tonic-gate } 960Sstevel@tonic-gate /* just a guess, but it looks like we will sleep */ 970Sstevel@tonic-gate if (ssp && lsp->count == 0) { 980Sstevel@tonic-gate begin_sleep = gethrtime(); 990Sstevel@tonic-gate if (lsp->count == 0) /* still looks like sleep */ 1000Sstevel@tonic-gate tdb_incr(ssp->sema_wait_sleep); 1010Sstevel@tonic-gate else /* we changed our mind */ 1020Sstevel@tonic-gate begin_sleep = 0; 1030Sstevel@tonic-gate } 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate if (lsp->type == USYNC_PROCESS) { /* kernel-level */ 1060Sstevel@tonic-gate set_parking_flag(self, 1); 1070Sstevel@tonic-gate if (self->ul_cursig != 0 || 1080Sstevel@tonic-gate (self->ul_cancelable && self->ul_cancel_pending)) 1090Sstevel@tonic-gate set_parking_flag(self, 0); 1100Sstevel@tonic-gate /* the kernel always does FIFO queueing */ 1110Sstevel@tonic-gate error = ___lwp_sema_timedwait(lsp, tsp, 1); 1120Sstevel@tonic-gate set_parking_flag(self, 0); 1130Sstevel@tonic-gate } else if (!udp->uberflags.uf_mt && /* single threaded */ 1140Sstevel@tonic-gate lsp->count != 0) { /* and non-blocking */ 1150Sstevel@tonic-gate /* 1160Sstevel@tonic-gate * Since we are single-threaded, we don't need the 1170Sstevel@tonic-gate * protection of queue_lock(). However, we do need 1180Sstevel@tonic-gate * to block signals while modifying the count. 1190Sstevel@tonic-gate */ 1200Sstevel@tonic-gate sigoff(self); 1210Sstevel@tonic-gate lsp->count--; 1220Sstevel@tonic-gate sigon(self); 1230Sstevel@tonic-gate } else { /* multithreaded or blocking */ 1240Sstevel@tonic-gate queue_head_t *qp; 1250Sstevel@tonic-gate ulwp_t *ulwp; 1260Sstevel@tonic-gate lwpid_t lwpid = 0; 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate qp = queue_lock(lsp, CV); 1290Sstevel@tonic-gate while (error == 0 && lsp->count == 0) { 1300Sstevel@tonic-gate /* 1310Sstevel@tonic-gate * SUSV3 requires FIFO queueing for semaphores, 1320Sstevel@tonic-gate * at least for SCHED_FIFO and SCHED_RR scheduling. 1330Sstevel@tonic-gate */ 134*6247Sraf enqueue(qp, self, 1); 1350Sstevel@tonic-gate lsp->sema_waiters = 1; 1360Sstevel@tonic-gate set_parking_flag(self, 1); 1370Sstevel@tonic-gate queue_unlock(qp); 1380Sstevel@tonic-gate /* 1390Sstevel@tonic-gate * We may have received SIGCANCEL before we 1400Sstevel@tonic-gate * called queue_lock(). If so and we are 1410Sstevel@tonic-gate * cancelable we should return EINTR. 1420Sstevel@tonic-gate */ 1430Sstevel@tonic-gate if (self->ul_cursig != 0 || 1440Sstevel@tonic-gate (self->ul_cancelable && self->ul_cancel_pending)) 1450Sstevel@tonic-gate set_parking_flag(self, 0); 1460Sstevel@tonic-gate error = __lwp_park(tsp, 0); 1470Sstevel@tonic-gate set_parking_flag(self, 0); 1480Sstevel@tonic-gate qp = queue_lock(lsp, CV); 1490Sstevel@tonic-gate if (self->ul_sleepq) /* timeout or spurious wakeup */ 150*6247Sraf lsp->sema_waiters = dequeue_self(qp); 1510Sstevel@tonic-gate } 1520Sstevel@tonic-gate if (error == 0) 1530Sstevel@tonic-gate lsp->count--; 1540Sstevel@tonic-gate if (lsp->count != 0 && lsp->sema_waiters) { 155*6247Sraf int more; 156*6247Sraf if ((ulwp = dequeue(qp, &more)) != NULL) { 1570Sstevel@tonic-gate no_preempt(self); 1580Sstevel@tonic-gate lwpid = ulwp->ul_lwpid; 1590Sstevel@tonic-gate } 160*6247Sraf lsp->sema_waiters = more; 1610Sstevel@tonic-gate } 1620Sstevel@tonic-gate queue_unlock(qp); 1630Sstevel@tonic-gate if (lwpid) { 1640Sstevel@tonic-gate (void) __lwp_unpark(lwpid); 1650Sstevel@tonic-gate preempt(self); 1660Sstevel@tonic-gate } 1670Sstevel@tonic-gate } 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate self->ul_wchan = NULL; 1700Sstevel@tonic-gate self->ul_sp = 0; 1710Sstevel@tonic-gate if (ssp) { 1720Sstevel@tonic-gate if (error == 0) { 1730Sstevel@tonic-gate /* we just decremented the count */ 1740Sstevel@tonic-gate count = lsp->count; 1750Sstevel@tonic-gate if (ssp->sema_min_count > count) 1760Sstevel@tonic-gate ssp->sema_min_count = count; 1770Sstevel@tonic-gate } 1780Sstevel@tonic-gate if (begin_sleep) 1790Sstevel@tonic-gate ssp->sema_wait_sleep_time += gethrtime() - begin_sleep; 1800Sstevel@tonic-gate } 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate if (error == EINTR) 1830Sstevel@tonic-gate _canceloff(); 1840Sstevel@tonic-gate else 1850Sstevel@tonic-gate _canceloff_nocancel(); 1860Sstevel@tonic-gate return (error); 1870Sstevel@tonic-gate } 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate #pragma weak sema_wait = _sema_wait 1900Sstevel@tonic-gate int 1910Sstevel@tonic-gate _sema_wait(sema_t *sp) 1920Sstevel@tonic-gate { 1930Sstevel@tonic-gate ASSERT(!curthread->ul_critical || curthread->ul_bindflags); 1940Sstevel@tonic-gate return (sema_wait_impl(sp, NULL)); 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate #pragma weak sema_reltimedwait = _sema_reltimedwait 1980Sstevel@tonic-gate int 1990Sstevel@tonic-gate _sema_reltimedwait(sema_t *sp, timespec_t *reltime) 2000Sstevel@tonic-gate { 2010Sstevel@tonic-gate timespec_t tslocal = *reltime; 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate ASSERT(!curthread->ul_critical || curthread->ul_bindflags); 2040Sstevel@tonic-gate return (sema_wait_impl(sp, &tslocal)); 2050Sstevel@tonic-gate } 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate #pragma weak sema_timedwait = _sema_timedwait 2080Sstevel@tonic-gate int 2090Sstevel@tonic-gate _sema_timedwait(sema_t *sp, timespec_t *abstime) 2100Sstevel@tonic-gate { 2110Sstevel@tonic-gate timespec_t tslocal; 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate ASSERT(!curthread->ul_critical || curthread->ul_bindflags); 2140Sstevel@tonic-gate abstime_to_reltime(CLOCK_REALTIME, abstime, &tslocal); 2150Sstevel@tonic-gate return (sema_wait_impl(sp, &tslocal)); 2160Sstevel@tonic-gate } 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate #pragma weak sema_trywait = _sema_trywait 2190Sstevel@tonic-gate int 2200Sstevel@tonic-gate _sema_trywait(sema_t *sp) 2210Sstevel@tonic-gate { 2220Sstevel@tonic-gate lwp_sema_t *lsp = (lwp_sema_t *)sp; 2230Sstevel@tonic-gate ulwp_t *self = curthread; 2240Sstevel@tonic-gate uberdata_t *udp = self->ul_uberdata; 2250Sstevel@tonic-gate tdb_sema_stats_t *ssp = SEMA_STATS(sp, udp); 2260Sstevel@tonic-gate uint_t count; 2270Sstevel@tonic-gate int error = 0; 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate ASSERT(!curthread->ul_critical || curthread->ul_bindflags); 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate if (ssp) 2320Sstevel@tonic-gate tdb_incr(ssp->sema_trywait); 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate if (lsp->type == USYNC_PROCESS) { /* kernel-level */ 2350Sstevel@tonic-gate error = __lwp_sema_trywait(lsp); 2360Sstevel@tonic-gate } else if (!udp->uberflags.uf_mt) { /* single threaded */ 2370Sstevel@tonic-gate sigoff(self); 2380Sstevel@tonic-gate if (lsp->count == 0) 2390Sstevel@tonic-gate error = EBUSY; 2400Sstevel@tonic-gate else 2410Sstevel@tonic-gate lsp->count--; 2420Sstevel@tonic-gate sigon(self); 2430Sstevel@tonic-gate } else { /* multithreaded */ 2440Sstevel@tonic-gate queue_head_t *qp; 2450Sstevel@tonic-gate ulwp_t *ulwp; 2460Sstevel@tonic-gate lwpid_t lwpid = 0; 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate qp = queue_lock(lsp, CV); 2490Sstevel@tonic-gate if (lsp->count == 0) 2500Sstevel@tonic-gate error = EBUSY; 2510Sstevel@tonic-gate else if (--lsp->count != 0 && lsp->sema_waiters) { 252*6247Sraf int more; 253*6247Sraf if ((ulwp = dequeue(qp, &more)) != NULL) { 2540Sstevel@tonic-gate no_preempt(self); 2550Sstevel@tonic-gate lwpid = ulwp->ul_lwpid; 2560Sstevel@tonic-gate } 257*6247Sraf lsp->sema_waiters = more; 2580Sstevel@tonic-gate } 2590Sstevel@tonic-gate queue_unlock(qp); 2600Sstevel@tonic-gate if (lwpid) { 2610Sstevel@tonic-gate (void) __lwp_unpark(lwpid); 2620Sstevel@tonic-gate preempt(self); 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate } 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate if (error == 0) { 2670Sstevel@tonic-gate if (ssp) { 2680Sstevel@tonic-gate /* we just decremented the count */ 2690Sstevel@tonic-gate count = lsp->count; 2700Sstevel@tonic-gate if (ssp->sema_min_count > count) 2710Sstevel@tonic-gate ssp->sema_min_count = count; 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate } else { 2740Sstevel@tonic-gate if (ssp) 2750Sstevel@tonic-gate tdb_incr(ssp->sema_trywait_fail); 2760Sstevel@tonic-gate if (__td_event_report(self, TD_LOCK_TRY, udp)) { 2770Sstevel@tonic-gate self->ul_td_evbuf.eventnum = TD_LOCK_TRY; 2780Sstevel@tonic-gate tdb_event(TD_LOCK_TRY, udp); 2790Sstevel@tonic-gate } 2800Sstevel@tonic-gate } 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate return (error); 2830Sstevel@tonic-gate } 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate #pragma weak sema_post = _sema_post 2860Sstevel@tonic-gate int 2870Sstevel@tonic-gate _sema_post(sema_t *sp) 2880Sstevel@tonic-gate { 2890Sstevel@tonic-gate lwp_sema_t *lsp = (lwp_sema_t *)sp; 2900Sstevel@tonic-gate ulwp_t *self = curthread; 2910Sstevel@tonic-gate uberdata_t *udp = self->ul_uberdata; 2920Sstevel@tonic-gate tdb_sema_stats_t *ssp = SEMA_STATS(sp, udp); 2930Sstevel@tonic-gate uint_t count; 2940Sstevel@tonic-gate int error = 0; 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate if (ssp) 2970Sstevel@tonic-gate tdb_incr(ssp->sema_post); 2980Sstevel@tonic-gate if (_semvaluemax == 0) 2990Sstevel@tonic-gate _semvaluemax = (uint32_t)_sysconf(_SC_SEM_VALUE_MAX); 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate if (lsp->type == USYNC_PROCESS) { /* kernel-level */ 3020Sstevel@tonic-gate error = __lwp_sema_post(lsp); 3030Sstevel@tonic-gate } else if (!udp->uberflags.uf_mt) { /* single threaded */ 3040Sstevel@tonic-gate sigoff(self); 3050Sstevel@tonic-gate if (lsp->count >= _semvaluemax) 3060Sstevel@tonic-gate error = EOVERFLOW; 3070Sstevel@tonic-gate else 3080Sstevel@tonic-gate lsp->count++; 3090Sstevel@tonic-gate sigon(self); 3100Sstevel@tonic-gate } else { /* multithreaded */ 3110Sstevel@tonic-gate queue_head_t *qp; 3120Sstevel@tonic-gate ulwp_t *ulwp; 3130Sstevel@tonic-gate lwpid_t lwpid = 0; 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate qp = queue_lock(lsp, CV); 3160Sstevel@tonic-gate if (lsp->count >= _semvaluemax) 3170Sstevel@tonic-gate error = EOVERFLOW; 3180Sstevel@tonic-gate else if (lsp->count++ == 0 && lsp->sema_waiters) { 319*6247Sraf int more; 320*6247Sraf if ((ulwp = dequeue(qp, &more)) != NULL) { 3210Sstevel@tonic-gate no_preempt(self); 3220Sstevel@tonic-gate lwpid = ulwp->ul_lwpid; 3230Sstevel@tonic-gate } 324*6247Sraf lsp->sema_waiters = more; 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate queue_unlock(qp); 3270Sstevel@tonic-gate if (lwpid) { 3280Sstevel@tonic-gate (void) __lwp_unpark(lwpid); 3290Sstevel@tonic-gate preempt(self); 3300Sstevel@tonic-gate } 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate if (error == 0) { 3340Sstevel@tonic-gate if (ssp) { 3350Sstevel@tonic-gate /* we just incremented the count */ 3360Sstevel@tonic-gate count = lsp->count; 3370Sstevel@tonic-gate if (ssp->sema_max_count < count) 3380Sstevel@tonic-gate ssp->sema_max_count = count; 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate } 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate return (error); 3430Sstevel@tonic-gate } 344