1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 1991-2003 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate /* 34*7c478bd9Sstevel@tonic-gate * UNIX Device Driver Interface functions 35*7c478bd9Sstevel@tonic-gate * This file contains the C-versions of putnext() and put(). 36*7c478bd9Sstevel@tonic-gate * Assembly language versions exist for some architectures. 37*7c478bd9Sstevel@tonic-gate */ 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/stream.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/thread.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/vtrace.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/strft.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/stack.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/archsystm.h> 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate /* 55*7c478bd9Sstevel@tonic-gate * Streams with many modules may create long chains of calls via putnext() which 56*7c478bd9Sstevel@tonic-gate * may exhaust stack space. When putnext detects that the stack space left is 57*7c478bd9Sstevel@tonic-gate * too small (less then PUT_STACK_NEEDED), the call chain is broken and 58*7c478bd9Sstevel@tonic-gate * further processing is delegated to the background thread via call to 59*7c478bd9Sstevel@tonic-gate * putnext_tail(). Unfortunately there is no generic solution with fixed stack 60*7c478bd9Sstevel@tonic-gate * size, and putnext() is recursive function, so this hack is a necessary evil. 61*7c478bd9Sstevel@tonic-gate * 62*7c478bd9Sstevel@tonic-gate * The redzone value is chosen dependent on the default stack size which is 8K 63*7c478bd9Sstevel@tonic-gate * on 32-bit kernels and on x86 and 16K on 64-bit kernels. The values are chosen 64*7c478bd9Sstevel@tonic-gate * empirically. For 64-bit kernels it is 5000 and for 32-bit kernels it is 2500. 65*7c478bd9Sstevel@tonic-gate * Experiments showed that 2500 is not enough for 64-bit kernels and 2048 is not 66*7c478bd9Sstevel@tonic-gate * enough for 32-bit. 67*7c478bd9Sstevel@tonic-gate * 68*7c478bd9Sstevel@tonic-gate * The redzone value is a tuneable rather then a constant to allow adjustments 69*7c478bd9Sstevel@tonic-gate * in the field. 70*7c478bd9Sstevel@tonic-gate * 71*7c478bd9Sstevel@tonic-gate * The check in PUT_STACK_NOTENOUGH is taken from segkp_map_red() function. It 72*7c478bd9Sstevel@tonic-gate * is possible to define it as a generic function exported by seg_kp, but 73*7c478bd9Sstevel@tonic-gate * 74*7c478bd9Sstevel@tonic-gate * a) It may sound like an open invitation to use the facility indiscriminately. 75*7c478bd9Sstevel@tonic-gate * b) It adds extra function call in putnext path. 76*7c478bd9Sstevel@tonic-gate * 77*7c478bd9Sstevel@tonic-gate * We keep a global counter `put_stack_notenough' which keeps track how many 78*7c478bd9Sstevel@tonic-gate * times the stack switching hack was used. 79*7c478bd9Sstevel@tonic-gate */ 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate static ulong_t put_stack_notenough; 82*7c478bd9Sstevel@tonic-gate 83*7c478bd9Sstevel@tonic-gate #ifdef _LP64 84*7c478bd9Sstevel@tonic-gate #define PUT_STACK_NEEDED 5000 85*7c478bd9Sstevel@tonic-gate #else 86*7c478bd9Sstevel@tonic-gate #define PUT_STACK_NEEDED 2500 87*7c478bd9Sstevel@tonic-gate #endif 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate int put_stack_needed = PUT_STACK_NEEDED; 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate #if defined(STACK_GROWTH_DOWN) 92*7c478bd9Sstevel@tonic-gate #define PUT_STACK_NOTENOUGH() \ 93*7c478bd9Sstevel@tonic-gate (((STACK_BIAS + (uintptr_t)getfp() - \ 94*7c478bd9Sstevel@tonic-gate (uintptr_t)curthread->t_stkbase) < put_stack_needed) && \ 95*7c478bd9Sstevel@tonic-gate ++put_stack_notenough) 96*7c478bd9Sstevel@tonic-gate #else 97*7c478bd9Sstevel@tonic-gate #error "STACK_GROWTH_DOWN undefined" 98*7c478bd9Sstevel@tonic-gate #endif 99*7c478bd9Sstevel@tonic-gate 100*7c478bd9Sstevel@tonic-gate boolean_t UseFastlocks = B_FALSE; 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate /* 103*7c478bd9Sstevel@tonic-gate * function: putnext() 104*7c478bd9Sstevel@tonic-gate * purpose: call the put routine of the queue linked to qp 105*7c478bd9Sstevel@tonic-gate * 106*7c478bd9Sstevel@tonic-gate * Note: this function is written to perform well on modern computer 107*7c478bd9Sstevel@tonic-gate * architectures by e.g. preloading values into registers and "smearing" out 108*7c478bd9Sstevel@tonic-gate * code. 109*7c478bd9Sstevel@tonic-gate * 110*7c478bd9Sstevel@tonic-gate * A note on the fastput mechanism. The most significant bit of a 111*7c478bd9Sstevel@tonic-gate * putcount is considered the "FASTPUT" bit. If set, then there is 112*7c478bd9Sstevel@tonic-gate * nothing stoping a concurrent put from occuring (note that putcounts 113*7c478bd9Sstevel@tonic-gate * are only allowed on CIPUT perimiters). If, however, it is cleared, 114*7c478bd9Sstevel@tonic-gate * then we need to take the normal lock path by aquiring the SQLOCK. 115*7c478bd9Sstevel@tonic-gate * This is a slowlock. When a thread starts exclusiveness, e.g. wants 116*7c478bd9Sstevel@tonic-gate * writer access, it will clear the FASTPUT bit, causing new threads 117*7c478bd9Sstevel@tonic-gate * to take the slowlock path. This assures that putcounts will not 118*7c478bd9Sstevel@tonic-gate * increase in value, so the want-writer does not need to constantly 119*7c478bd9Sstevel@tonic-gate * aquire the putlocks to sum the putcounts. This does have the 120*7c478bd9Sstevel@tonic-gate * possibility of having the count drop right after reading, but that 121*7c478bd9Sstevel@tonic-gate * is no different than aquiring, reading and then releasing. However, 122*7c478bd9Sstevel@tonic-gate * in this mode, it cannot go up, so eventually they will drop to zero 123*7c478bd9Sstevel@tonic-gate * and the want-writer can proceed. 124*7c478bd9Sstevel@tonic-gate * 125*7c478bd9Sstevel@tonic-gate * If the FASTPUT bit is set, or in the slowlock path we see that there 126*7c478bd9Sstevel@tonic-gate * are no writers or want-writers, we make the choice of calling the 127*7c478bd9Sstevel@tonic-gate * putproc, or a "fast-fill_syncq". The fast-fill is a fill with 128*7c478bd9Sstevel@tonic-gate * immediate intention to drain. This is done because there are 129*7c478bd9Sstevel@tonic-gate * messages already at the queue waiting to drain. To preserve message 130*7c478bd9Sstevel@tonic-gate * ordering, we need to put this message at the end, and pickup the 131*7c478bd9Sstevel@tonic-gate * messages at the beginning. We call the macro that actually 132*7c478bd9Sstevel@tonic-gate * enqueues the message on the queue, and then call qdrain_syncq. If 133*7c478bd9Sstevel@tonic-gate * there is already a drainer, we just return. We could make that 134*7c478bd9Sstevel@tonic-gate * check before calling qdrain_syncq, but it is a little more clear 135*7c478bd9Sstevel@tonic-gate * to have qdrain_syncq do this (we might try the above optimization 136*7c478bd9Sstevel@tonic-gate * as this behavior evolves). qdrain_syncq assumes that SQ_EXCL is set 137*7c478bd9Sstevel@tonic-gate * already if this is a non-CIPUT perimiter, and that an appropriate 138*7c478bd9Sstevel@tonic-gate * claim has been made. So we do all that work before dropping the 139*7c478bd9Sstevel@tonic-gate * SQLOCK with our claim. 140*7c478bd9Sstevel@tonic-gate * 141*7c478bd9Sstevel@tonic-gate * If we cannot proceed with the putproc/fast-fill, we just fall 142*7c478bd9Sstevel@tonic-gate * through to the qfill_syncq, and then tail processing. If state 143*7c478bd9Sstevel@tonic-gate * has changed in that cycle, or wakeups are needed, it will occur 144*7c478bd9Sstevel@tonic-gate * there. 145*7c478bd9Sstevel@tonic-gate */ 146*7c478bd9Sstevel@tonic-gate void 147*7c478bd9Sstevel@tonic-gate putnext(queue_t *qp, mblk_t *mp) 148*7c478bd9Sstevel@tonic-gate { 149*7c478bd9Sstevel@tonic-gate queue_t *fqp = qp; /* For strft tracing */ 150*7c478bd9Sstevel@tonic-gate syncq_t *sq; 151*7c478bd9Sstevel@tonic-gate uint16_t flags; 152*7c478bd9Sstevel@tonic-gate uint16_t drain_mask; 153*7c478bd9Sstevel@tonic-gate struct qinit *qi; 154*7c478bd9Sstevel@tonic-gate int (*putproc)(); 155*7c478bd9Sstevel@tonic-gate struct stdata *stp; 156*7c478bd9Sstevel@tonic-gate int ix; 157*7c478bd9Sstevel@tonic-gate boolean_t queued = B_FALSE; 158*7c478bd9Sstevel@tonic-gate kmutex_t *sdlock = NULL; 159*7c478bd9Sstevel@tonic-gate kmutex_t *sqciplock = NULL; 160*7c478bd9Sstevel@tonic-gate ushort_t *sqcipcount = NULL; 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_STREAMS_FR, TR_PUTNEXT_START, 163*7c478bd9Sstevel@tonic-gate "putnext_start:(%p, %p)", qp, mp); 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate ASSERT(mp->b_datap->db_ref != 0); 166*7c478bd9Sstevel@tonic-gate ASSERT(mp->b_next == NULL && mp->b_prev == NULL); 167*7c478bd9Sstevel@tonic-gate stp = STREAM(qp); 168*7c478bd9Sstevel@tonic-gate ASSERT(stp != NULL); 169*7c478bd9Sstevel@tonic-gate if (stp->sd_ciputctrl != NULL) { 170*7c478bd9Sstevel@tonic-gate ix = CPU->cpu_seqid & stp->sd_nciputctrl; 171*7c478bd9Sstevel@tonic-gate sdlock = &stp->sd_ciputctrl[ix].ciputctrl_lock; 172*7c478bd9Sstevel@tonic-gate mutex_enter(sdlock); 173*7c478bd9Sstevel@tonic-gate } else { 174*7c478bd9Sstevel@tonic-gate mutex_enter(sdlock = &stp->sd_lock); 175*7c478bd9Sstevel@tonic-gate } 176*7c478bd9Sstevel@tonic-gate qp = qp->q_next; 177*7c478bd9Sstevel@tonic-gate sq = qp->q_syncq; 178*7c478bd9Sstevel@tonic-gate ASSERT(sq != NULL); 179*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(SQLOCK(sq))); 180*7c478bd9Sstevel@tonic-gate qi = qp->q_qinfo; 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate if (sq->sq_ciputctrl != NULL) { 183*7c478bd9Sstevel@tonic-gate /* fastlock: */ 184*7c478bd9Sstevel@tonic-gate ASSERT(sq->sq_flags & SQ_CIPUT); 185*7c478bd9Sstevel@tonic-gate ix = CPU->cpu_seqid & sq->sq_nciputctrl; 186*7c478bd9Sstevel@tonic-gate sqciplock = &sq->sq_ciputctrl[ix].ciputctrl_lock; 187*7c478bd9Sstevel@tonic-gate sqcipcount = &sq->sq_ciputctrl[ix].ciputctrl_count; 188*7c478bd9Sstevel@tonic-gate mutex_enter(sqciplock); 189*7c478bd9Sstevel@tonic-gate if (!((*sqcipcount) & SQ_FASTPUT) || 190*7c478bd9Sstevel@tonic-gate (sq->sq_flags & (SQ_STAYAWAY|SQ_EXCL|SQ_EVENTS))) { 191*7c478bd9Sstevel@tonic-gate mutex_exit(sqciplock); 192*7c478bd9Sstevel@tonic-gate sqciplock = NULL; 193*7c478bd9Sstevel@tonic-gate goto slowlock; 194*7c478bd9Sstevel@tonic-gate } 195*7c478bd9Sstevel@tonic-gate mutex_exit(sdlock); 196*7c478bd9Sstevel@tonic-gate (*sqcipcount)++; 197*7c478bd9Sstevel@tonic-gate ASSERT(*sqcipcount != 0); 198*7c478bd9Sstevel@tonic-gate queued = qp->q_sqflags & Q_SQQUEUED; 199*7c478bd9Sstevel@tonic-gate mutex_exit(sqciplock); 200*7c478bd9Sstevel@tonic-gate } else { 201*7c478bd9Sstevel@tonic-gate slowlock: 202*7c478bd9Sstevel@tonic-gate ASSERT(sqciplock == NULL); 203*7c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 204*7c478bd9Sstevel@tonic-gate mutex_exit(sdlock); 205*7c478bd9Sstevel@tonic-gate flags = sq->sq_flags; 206*7c478bd9Sstevel@tonic-gate /* 207*7c478bd9Sstevel@tonic-gate * We are going to drop SQLOCK, so make a claim to prevent syncq 208*7c478bd9Sstevel@tonic-gate * from closing. 209*7c478bd9Sstevel@tonic-gate */ 210*7c478bd9Sstevel@tonic-gate sq->sq_count++; 211*7c478bd9Sstevel@tonic-gate ASSERT(sq->sq_count != 0); /* Wraparound */ 212*7c478bd9Sstevel@tonic-gate /* 213*7c478bd9Sstevel@tonic-gate * If there are writers or exclusive waiters, there is not much 214*7c478bd9Sstevel@tonic-gate * we can do. Place the message on the syncq and schedule a 215*7c478bd9Sstevel@tonic-gate * background thread to drain it. 216*7c478bd9Sstevel@tonic-gate * 217*7c478bd9Sstevel@tonic-gate * Also if we are approaching end of stack, fill the syncq and 218*7c478bd9Sstevel@tonic-gate * switch processing to a background thread - see comments on 219*7c478bd9Sstevel@tonic-gate * top. 220*7c478bd9Sstevel@tonic-gate */ 221*7c478bd9Sstevel@tonic-gate if ((flags & (SQ_STAYAWAY|SQ_EXCL|SQ_EVENTS)) || 222*7c478bd9Sstevel@tonic-gate (sq->sq_needexcl != 0) || PUT_STACK_NOTENOUGH()) { 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate TRACE_3(TR_FAC_STREAMS_FR, TR_PUTNEXT_END, 225*7c478bd9Sstevel@tonic-gate "putnext_end:(%p, %p, %p) SQ_EXCL fill", 226*7c478bd9Sstevel@tonic-gate qp, mp, sq); 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate /* 229*7c478bd9Sstevel@tonic-gate * NOTE: qfill_syncq will need QLOCK. It is safe to drop 230*7c478bd9Sstevel@tonic-gate * SQLOCK because positive sq_count keeps the syncq from 231*7c478bd9Sstevel@tonic-gate * closing. 232*7c478bd9Sstevel@tonic-gate */ 233*7c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate qfill_syncq(sq, qp, mp); 236*7c478bd9Sstevel@tonic-gate /* 237*7c478bd9Sstevel@tonic-gate * NOTE: after the call to qfill_syncq() qp may be 238*7c478bd9Sstevel@tonic-gate * closed, both qp and sq should not be referenced at 239*7c478bd9Sstevel@tonic-gate * this point. 240*7c478bd9Sstevel@tonic-gate * 241*7c478bd9Sstevel@tonic-gate * This ASSERT is located here to prevent stack frame 242*7c478bd9Sstevel@tonic-gate * consumption in the DEBUG code. 243*7c478bd9Sstevel@tonic-gate */ 244*7c478bd9Sstevel@tonic-gate ASSERT(sqciplock == NULL); 245*7c478bd9Sstevel@tonic-gate return; 246*7c478bd9Sstevel@tonic-gate } 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate queued = qp->q_sqflags & Q_SQQUEUED; 249*7c478bd9Sstevel@tonic-gate /* 250*7c478bd9Sstevel@tonic-gate * If not a concurrent perimiter, we need to acquire 251*7c478bd9Sstevel@tonic-gate * it exclusively. It could not have been previously 252*7c478bd9Sstevel@tonic-gate * set since we held the SQLOCK before testing 253*7c478bd9Sstevel@tonic-gate * SQ_GOAWAY above (which includes SQ_EXCL). 254*7c478bd9Sstevel@tonic-gate * We do this here because we hold the SQLOCK, and need 255*7c478bd9Sstevel@tonic-gate * to make this state change BEFORE dropping it. 256*7c478bd9Sstevel@tonic-gate */ 257*7c478bd9Sstevel@tonic-gate if (!(flags & SQ_CIPUT)) { 258*7c478bd9Sstevel@tonic-gate ASSERT((sq->sq_flags & SQ_EXCL) == 0); 259*7c478bd9Sstevel@tonic-gate ASSERT(!(sq->sq_type & SQ_CIPUT)); 260*7c478bd9Sstevel@tonic-gate sq->sq_flags |= SQ_EXCL; 261*7c478bd9Sstevel@tonic-gate } 262*7c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 263*7c478bd9Sstevel@tonic-gate } 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate ASSERT((sq->sq_flags & (SQ_EXCL|SQ_CIPUT))); 266*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(SQLOCK(sq))); 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate /* 269*7c478bd9Sstevel@tonic-gate * We now have a claim on the syncq, we are either going to 270*7c478bd9Sstevel@tonic-gate * put the message on the syncq and then drain it, or we are 271*7c478bd9Sstevel@tonic-gate * going to call the putproc(). 272*7c478bd9Sstevel@tonic-gate */ 273*7c478bd9Sstevel@tonic-gate putproc = qi->qi_putp; 274*7c478bd9Sstevel@tonic-gate if (!queued) { 275*7c478bd9Sstevel@tonic-gate STR_FTEVENT_MSG(mp, fqp, FTEV_PUTNEXT, mp->b_rptr - 276*7c478bd9Sstevel@tonic-gate mp->b_datap->db_base); 277*7c478bd9Sstevel@tonic-gate (*putproc)(qp, mp); 278*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(SQLOCK(sq))); 279*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(QLOCK(qp))); 280*7c478bd9Sstevel@tonic-gate } else { 281*7c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(qp)); 282*7c478bd9Sstevel@tonic-gate /* 283*7c478bd9Sstevel@tonic-gate * If there are no messages in front of us, just call putproc(), 284*7c478bd9Sstevel@tonic-gate * otherwise enqueue the message and drain the queue. 285*7c478bd9Sstevel@tonic-gate */ 286*7c478bd9Sstevel@tonic-gate if (qp->q_syncqmsgs == 0) { 287*7c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(qp)); 288*7c478bd9Sstevel@tonic-gate STR_FTEVENT_MSG(mp, fqp, FTEV_PUTNEXT, mp->b_rptr - 289*7c478bd9Sstevel@tonic-gate mp->b_datap->db_base); 290*7c478bd9Sstevel@tonic-gate (*putproc)(qp, mp); 291*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(SQLOCK(sq))); 292*7c478bd9Sstevel@tonic-gate } else { 293*7c478bd9Sstevel@tonic-gate /* 294*7c478bd9Sstevel@tonic-gate * We are doing a fill with the intent to 295*7c478bd9Sstevel@tonic-gate * drain (meaning we are filling because 296*7c478bd9Sstevel@tonic-gate * there are messages in front of us ane we 297*7c478bd9Sstevel@tonic-gate * need to preserve message ordering) 298*7c478bd9Sstevel@tonic-gate * Therefore, put the message on the queue 299*7c478bd9Sstevel@tonic-gate * and call qdrain_syncq (must be done with 300*7c478bd9Sstevel@tonic-gate * the QLOCK held). 301*7c478bd9Sstevel@tonic-gate */ 302*7c478bd9Sstevel@tonic-gate STR_FTEVENT_MSG(mp, fqp, FTEV_PUTNEXT, 303*7c478bd9Sstevel@tonic-gate mp->b_rptr - mp->b_datap->db_base); 304*7c478bd9Sstevel@tonic-gate 305*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 306*7c478bd9Sstevel@tonic-gate /* 307*7c478bd9Sstevel@tonic-gate * These two values were in the original code for 308*7c478bd9Sstevel@tonic-gate * all syncq messages. This is unnecessary in 309*7c478bd9Sstevel@tonic-gate * the current implementation, but was retained 310*7c478bd9Sstevel@tonic-gate * in debug mode as it is usefull to know where 311*7c478bd9Sstevel@tonic-gate * problems occur. 312*7c478bd9Sstevel@tonic-gate */ 313*7c478bd9Sstevel@tonic-gate mp->b_queue = qp; 314*7c478bd9Sstevel@tonic-gate mp->b_prev = (mblk_t *)putproc; 315*7c478bd9Sstevel@tonic-gate #endif 316*7c478bd9Sstevel@tonic-gate SQPUT_MP(qp, mp); 317*7c478bd9Sstevel@tonic-gate qdrain_syncq(sq, qp); 318*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(QLOCK(qp))); 319*7c478bd9Sstevel@tonic-gate } 320*7c478bd9Sstevel@tonic-gate } 321*7c478bd9Sstevel@tonic-gate /* 322*7c478bd9Sstevel@tonic-gate * Before we release our claim, we need to see if any 323*7c478bd9Sstevel@tonic-gate * events were posted. If the syncq is SQ_EXCL && SQ_QUEUED, 324*7c478bd9Sstevel@tonic-gate * we were responsible for going exclusive and, therefore, 325*7c478bd9Sstevel@tonic-gate * are resposible for draining. 326*7c478bd9Sstevel@tonic-gate */ 327*7c478bd9Sstevel@tonic-gate if (sq->sq_flags & (SQ_EXCL)) { 328*7c478bd9Sstevel@tonic-gate drain_mask = 0; 329*7c478bd9Sstevel@tonic-gate } else { 330*7c478bd9Sstevel@tonic-gate drain_mask = SQ_QUEUED; 331*7c478bd9Sstevel@tonic-gate } 332*7c478bd9Sstevel@tonic-gate 333*7c478bd9Sstevel@tonic-gate if (sqciplock != NULL) { 334*7c478bd9Sstevel@tonic-gate mutex_enter(sqciplock); 335*7c478bd9Sstevel@tonic-gate flags = sq->sq_flags; 336*7c478bd9Sstevel@tonic-gate ASSERT(flags & SQ_CIPUT); 337*7c478bd9Sstevel@tonic-gate /* SQ_EXCL could have been set by qwriter_inner */ 338*7c478bd9Sstevel@tonic-gate if ((flags & (SQ_EXCL|SQ_TAIL)) || sq->sq_needexcl) { 339*7c478bd9Sstevel@tonic-gate /* 340*7c478bd9Sstevel@tonic-gate * we need SQLOCK to handle 341*7c478bd9Sstevel@tonic-gate * wakeups/drains/flags change. sqciplock 342*7c478bd9Sstevel@tonic-gate * is needed to decrement sqcipcount. 343*7c478bd9Sstevel@tonic-gate * SQLOCK has to be grabbed before sqciplock 344*7c478bd9Sstevel@tonic-gate * for lock ordering purposes. 345*7c478bd9Sstevel@tonic-gate * after sqcipcount is decremented some lock 346*7c478bd9Sstevel@tonic-gate * still needs to be held to make sure 347*7c478bd9Sstevel@tonic-gate * syncq won't get freed on us. 348*7c478bd9Sstevel@tonic-gate * 349*7c478bd9Sstevel@tonic-gate * To prevent deadlocks we try to grab SQLOCK and if it 350*7c478bd9Sstevel@tonic-gate * is held already we drop sqciplock, acquire SQLOCK and 351*7c478bd9Sstevel@tonic-gate * reacqwire sqciplock again. 352*7c478bd9Sstevel@tonic-gate */ 353*7c478bd9Sstevel@tonic-gate if (mutex_tryenter(SQLOCK(sq)) == 0) { 354*7c478bd9Sstevel@tonic-gate mutex_exit(sqciplock); 355*7c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 356*7c478bd9Sstevel@tonic-gate mutex_enter(sqciplock); 357*7c478bd9Sstevel@tonic-gate } 358*7c478bd9Sstevel@tonic-gate flags = sq->sq_flags; 359*7c478bd9Sstevel@tonic-gate ASSERT(*sqcipcount != 0); 360*7c478bd9Sstevel@tonic-gate (*sqcipcount)--; 361*7c478bd9Sstevel@tonic-gate mutex_exit(sqciplock); 362*7c478bd9Sstevel@tonic-gate } else { 363*7c478bd9Sstevel@tonic-gate ASSERT(*sqcipcount != 0); 364*7c478bd9Sstevel@tonic-gate (*sqcipcount)--; 365*7c478bd9Sstevel@tonic-gate mutex_exit(sqciplock); 366*7c478bd9Sstevel@tonic-gate TRACE_3(TR_FAC_STREAMS_FR, TR_PUTNEXT_END, 367*7c478bd9Sstevel@tonic-gate "putnext_end:(%p, %p, %p) done", qp, mp, sq); 368*7c478bd9Sstevel@tonic-gate return; 369*7c478bd9Sstevel@tonic-gate } 370*7c478bd9Sstevel@tonic-gate } else { 371*7c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 372*7c478bd9Sstevel@tonic-gate flags = sq->sq_flags; 373*7c478bd9Sstevel@tonic-gate ASSERT(sq->sq_count != 0); 374*7c478bd9Sstevel@tonic-gate sq->sq_count--; 375*7c478bd9Sstevel@tonic-gate } 376*7c478bd9Sstevel@tonic-gate if ((flags & (SQ_TAIL)) || sq->sq_needexcl) { 377*7c478bd9Sstevel@tonic-gate putnext_tail(sq, qp, (flags & ~drain_mask)); 378*7c478bd9Sstevel@tonic-gate /* 379*7c478bd9Sstevel@tonic-gate * The only purpose of this ASSERT is to preserve calling stack 380*7c478bd9Sstevel@tonic-gate * in DEBUG kernel. 381*7c478bd9Sstevel@tonic-gate */ 382*7c478bd9Sstevel@tonic-gate ASSERT(sq != NULL); 383*7c478bd9Sstevel@tonic-gate return; 384*7c478bd9Sstevel@tonic-gate } 385*7c478bd9Sstevel@tonic-gate ASSERT((sq->sq_flags & (SQ_EXCL|SQ_CIPUT)) || queued); 386*7c478bd9Sstevel@tonic-gate ASSERT((flags & (SQ_EXCL|SQ_CIPUT)) || queued); 387*7c478bd9Sstevel@tonic-gate /* 388*7c478bd9Sstevel@tonic-gate * Safe to always drop SQ_EXCL: 389*7c478bd9Sstevel@tonic-gate * Not SQ_CIPUT means we set SQ_EXCL above 390*7c478bd9Sstevel@tonic-gate * For SQ_CIPUT SQ_EXCL will only be set if the put 391*7c478bd9Sstevel@tonic-gate * procedure did a qwriter(INNER) in which case 392*7c478bd9Sstevel@tonic-gate * nobody else is in the inner perimeter and we 393*7c478bd9Sstevel@tonic-gate * are exiting. 394*7c478bd9Sstevel@tonic-gate * 395*7c478bd9Sstevel@tonic-gate * I would like to make the following assertion: 396*7c478bd9Sstevel@tonic-gate * 397*7c478bd9Sstevel@tonic-gate * ASSERT((flags & (SQ_EXCL|SQ_CIPUT)) != (SQ_EXCL|SQ_CIPUT) || 398*7c478bd9Sstevel@tonic-gate * sq->sq_count == 0); 399*7c478bd9Sstevel@tonic-gate * 400*7c478bd9Sstevel@tonic-gate * which indicates that if we are both putshared and exclusive, 401*7c478bd9Sstevel@tonic-gate * we became exclusive while executing the putproc, and the only 402*7c478bd9Sstevel@tonic-gate * claim on the syncq was the one we dropped a few lines above. 403*7c478bd9Sstevel@tonic-gate * But other threads that enter putnext while the syncq is exclusive 404*7c478bd9Sstevel@tonic-gate * need to make a claim as they may need to drop SQLOCK in the 405*7c478bd9Sstevel@tonic-gate * has_writers case to avoid deadlocks. If these threads are 406*7c478bd9Sstevel@tonic-gate * delayed or preempted, it is possible that the writer thread can 407*7c478bd9Sstevel@tonic-gate * find out that there are other claims making the (sq_count == 0) 408*7c478bd9Sstevel@tonic-gate * test invalid. 409*7c478bd9Sstevel@tonic-gate */ 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate sq->sq_flags = flags & ~SQ_EXCL; 412*7c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 413*7c478bd9Sstevel@tonic-gate TRACE_3(TR_FAC_STREAMS_FR, TR_PUTNEXT_END, 414*7c478bd9Sstevel@tonic-gate "putnext_end:(%p, %p, %p) done", qp, mp, sq); 415*7c478bd9Sstevel@tonic-gate } 416*7c478bd9Sstevel@tonic-gate 417*7c478bd9Sstevel@tonic-gate 418*7c478bd9Sstevel@tonic-gate /* 419*7c478bd9Sstevel@tonic-gate * wrapper for qi_putp entry in module ops vec. 420*7c478bd9Sstevel@tonic-gate * implements asynchronous putnext(). 421*7c478bd9Sstevel@tonic-gate * Note, that unlike putnext(), this routine is NOT optimized for the 422*7c478bd9Sstevel@tonic-gate * fastpath. Calling this routine will grab whatever locks are necessary 423*7c478bd9Sstevel@tonic-gate * to protect the stream head, q_next, and syncq's. 424*7c478bd9Sstevel@tonic-gate * And since it is in the normal locks path, we do not use putlocks if 425*7c478bd9Sstevel@tonic-gate * they exist (though this can be changed by swapping the value of 426*7c478bd9Sstevel@tonic-gate * UseFastlocks). 427*7c478bd9Sstevel@tonic-gate */ 428*7c478bd9Sstevel@tonic-gate void 429*7c478bd9Sstevel@tonic-gate put(queue_t *qp, mblk_t *mp) 430*7c478bd9Sstevel@tonic-gate { 431*7c478bd9Sstevel@tonic-gate queue_t *fqp = qp; /* For strft tracing */ 432*7c478bd9Sstevel@tonic-gate syncq_t *sq; 433*7c478bd9Sstevel@tonic-gate uint16_t flags; 434*7c478bd9Sstevel@tonic-gate uint16_t drain_mask; 435*7c478bd9Sstevel@tonic-gate struct qinit *qi; 436*7c478bd9Sstevel@tonic-gate int (*putproc)(); 437*7c478bd9Sstevel@tonic-gate int ix; 438*7c478bd9Sstevel@tonic-gate boolean_t queued = B_FALSE; 439*7c478bd9Sstevel@tonic-gate kmutex_t *sqciplock = NULL; 440*7c478bd9Sstevel@tonic-gate ushort_t *sqcipcount = NULL; 441*7c478bd9Sstevel@tonic-gate 442*7c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_STREAMS_FR, TR_PUT_START, 443*7c478bd9Sstevel@tonic-gate "put:(%X, %X)", qp, mp); 444*7c478bd9Sstevel@tonic-gate ASSERT(mp->b_datap->db_ref != 0); 445*7c478bd9Sstevel@tonic-gate ASSERT(mp->b_next == NULL && mp->b_prev == NULL); 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate sq = qp->q_syncq; 448*7c478bd9Sstevel@tonic-gate ASSERT(sq != NULL); 449*7c478bd9Sstevel@tonic-gate qi = qp->q_qinfo; 450*7c478bd9Sstevel@tonic-gate 451*7c478bd9Sstevel@tonic-gate if (UseFastlocks && sq->sq_ciputctrl != NULL) { 452*7c478bd9Sstevel@tonic-gate /* fastlock: */ 453*7c478bd9Sstevel@tonic-gate ASSERT(sq->sq_flags & SQ_CIPUT); 454*7c478bd9Sstevel@tonic-gate ix = CPU->cpu_seqid & sq->sq_nciputctrl; 455*7c478bd9Sstevel@tonic-gate sqciplock = &sq->sq_ciputctrl[ix].ciputctrl_lock; 456*7c478bd9Sstevel@tonic-gate sqcipcount = &sq->sq_ciputctrl[ix].ciputctrl_count; 457*7c478bd9Sstevel@tonic-gate mutex_enter(sqciplock); 458*7c478bd9Sstevel@tonic-gate if (!((*sqcipcount) & SQ_FASTPUT) || 459*7c478bd9Sstevel@tonic-gate (sq->sq_flags & (SQ_STAYAWAY|SQ_EXCL|SQ_EVENTS))) { 460*7c478bd9Sstevel@tonic-gate mutex_exit(sqciplock); 461*7c478bd9Sstevel@tonic-gate sqciplock = NULL; 462*7c478bd9Sstevel@tonic-gate goto slowlock; 463*7c478bd9Sstevel@tonic-gate } 464*7c478bd9Sstevel@tonic-gate (*sqcipcount)++; 465*7c478bd9Sstevel@tonic-gate ASSERT(*sqcipcount != 0); 466*7c478bd9Sstevel@tonic-gate queued = qp->q_sqflags & Q_SQQUEUED; 467*7c478bd9Sstevel@tonic-gate mutex_exit(sqciplock); 468*7c478bd9Sstevel@tonic-gate } else { 469*7c478bd9Sstevel@tonic-gate slowlock: 470*7c478bd9Sstevel@tonic-gate ASSERT(sqciplock == NULL); 471*7c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 472*7c478bd9Sstevel@tonic-gate flags = sq->sq_flags; 473*7c478bd9Sstevel@tonic-gate /* 474*7c478bd9Sstevel@tonic-gate * We are going to drop SQLOCK, so make a claim to prevent syncq 475*7c478bd9Sstevel@tonic-gate * from closing. 476*7c478bd9Sstevel@tonic-gate */ 477*7c478bd9Sstevel@tonic-gate sq->sq_count++; 478*7c478bd9Sstevel@tonic-gate ASSERT(sq->sq_count != 0); /* Wraparound */ 479*7c478bd9Sstevel@tonic-gate /* 480*7c478bd9Sstevel@tonic-gate * If there are writers or exclusive waiters, there is not much 481*7c478bd9Sstevel@tonic-gate * we can do. Place the message on the syncq and schedule a 482*7c478bd9Sstevel@tonic-gate * background thread to drain it. 483*7c478bd9Sstevel@tonic-gate * 484*7c478bd9Sstevel@tonic-gate * Also if we are approaching end of stack, fill the syncq and 485*7c478bd9Sstevel@tonic-gate * switch processing to a background thread - see comments on 486*7c478bd9Sstevel@tonic-gate * top. 487*7c478bd9Sstevel@tonic-gate */ 488*7c478bd9Sstevel@tonic-gate if ((flags & (SQ_STAYAWAY|SQ_EXCL|SQ_EVENTS)) || 489*7c478bd9Sstevel@tonic-gate (sq->sq_needexcl != 0) || PUT_STACK_NOTENOUGH()) { 490*7c478bd9Sstevel@tonic-gate 491*7c478bd9Sstevel@tonic-gate TRACE_3(TR_FAC_STREAMS_FR, TR_PUTNEXT_END, 492*7c478bd9Sstevel@tonic-gate "putnext_end:(%p, %p, %p) SQ_EXCL fill", 493*7c478bd9Sstevel@tonic-gate qp, mp, sq); 494*7c478bd9Sstevel@tonic-gate 495*7c478bd9Sstevel@tonic-gate /* 496*7c478bd9Sstevel@tonic-gate * NOTE: qfill_syncq will need QLOCK. It is safe to drop 497*7c478bd9Sstevel@tonic-gate * SQLOCK because positive sq_count keeps the syncq from 498*7c478bd9Sstevel@tonic-gate * closing. 499*7c478bd9Sstevel@tonic-gate */ 500*7c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate qfill_syncq(sq, qp, mp); 503*7c478bd9Sstevel@tonic-gate /* 504*7c478bd9Sstevel@tonic-gate * NOTE: after the call to qfill_syncq() qp may be 505*7c478bd9Sstevel@tonic-gate * closed, both qp and sq should not be referenced at 506*7c478bd9Sstevel@tonic-gate * this point. 507*7c478bd9Sstevel@tonic-gate * 508*7c478bd9Sstevel@tonic-gate * This ASSERT is located here to prevent stack frame 509*7c478bd9Sstevel@tonic-gate * consumption in the DEBUG code. 510*7c478bd9Sstevel@tonic-gate */ 511*7c478bd9Sstevel@tonic-gate ASSERT(sqciplock == NULL); 512*7c478bd9Sstevel@tonic-gate return; 513*7c478bd9Sstevel@tonic-gate } 514*7c478bd9Sstevel@tonic-gate 515*7c478bd9Sstevel@tonic-gate queued = qp->q_sqflags & Q_SQQUEUED; 516*7c478bd9Sstevel@tonic-gate /* 517*7c478bd9Sstevel@tonic-gate * If not a concurrent perimiter, we need to acquire 518*7c478bd9Sstevel@tonic-gate * it exclusively. It could not have been previously 519*7c478bd9Sstevel@tonic-gate * set since we held the SQLOCK before testing 520*7c478bd9Sstevel@tonic-gate * SQ_GOAWAY above (which includes SQ_EXCL). 521*7c478bd9Sstevel@tonic-gate * We do this here because we hold the SQLOCK, and need 522*7c478bd9Sstevel@tonic-gate * to make this state change BEFORE dropping it. 523*7c478bd9Sstevel@tonic-gate */ 524*7c478bd9Sstevel@tonic-gate if (!(flags & SQ_CIPUT)) { 525*7c478bd9Sstevel@tonic-gate ASSERT((sq->sq_flags & SQ_EXCL) == 0); 526*7c478bd9Sstevel@tonic-gate ASSERT(!(sq->sq_type & SQ_CIPUT)); 527*7c478bd9Sstevel@tonic-gate sq->sq_flags |= SQ_EXCL; 528*7c478bd9Sstevel@tonic-gate } 529*7c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 530*7c478bd9Sstevel@tonic-gate } 531*7c478bd9Sstevel@tonic-gate 532*7c478bd9Sstevel@tonic-gate ASSERT((sq->sq_flags & (SQ_EXCL|SQ_CIPUT))); 533*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(SQLOCK(sq))); 534*7c478bd9Sstevel@tonic-gate 535*7c478bd9Sstevel@tonic-gate /* 536*7c478bd9Sstevel@tonic-gate * We now have a claim on the syncq, we are either going to 537*7c478bd9Sstevel@tonic-gate * put the message on the syncq and then drain it, or we are 538*7c478bd9Sstevel@tonic-gate * going to call the putproc(). 539*7c478bd9Sstevel@tonic-gate */ 540*7c478bd9Sstevel@tonic-gate putproc = qi->qi_putp; 541*7c478bd9Sstevel@tonic-gate if (!queued) { 542*7c478bd9Sstevel@tonic-gate STR_FTEVENT_MSG(mp, fqp, FTEV_PUTNEXT, mp->b_rptr - 543*7c478bd9Sstevel@tonic-gate mp->b_datap->db_base); 544*7c478bd9Sstevel@tonic-gate (*putproc)(qp, mp); 545*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(SQLOCK(sq))); 546*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(QLOCK(qp))); 547*7c478bd9Sstevel@tonic-gate } else { 548*7c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(qp)); 549*7c478bd9Sstevel@tonic-gate /* 550*7c478bd9Sstevel@tonic-gate * If there are no messages in front of us, just call putproc(), 551*7c478bd9Sstevel@tonic-gate * otherwise enqueue the message and drain the queue. 552*7c478bd9Sstevel@tonic-gate */ 553*7c478bd9Sstevel@tonic-gate if (qp->q_syncqmsgs == 0) { 554*7c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(qp)); 555*7c478bd9Sstevel@tonic-gate STR_FTEVENT_MSG(mp, fqp, FTEV_PUTNEXT, mp->b_rptr - 556*7c478bd9Sstevel@tonic-gate mp->b_datap->db_base); 557*7c478bd9Sstevel@tonic-gate (*putproc)(qp, mp); 558*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(SQLOCK(sq))); 559*7c478bd9Sstevel@tonic-gate } else { 560*7c478bd9Sstevel@tonic-gate /* 561*7c478bd9Sstevel@tonic-gate * We are doing a fill with the intent to 562*7c478bd9Sstevel@tonic-gate * drain (meaning we are filling because 563*7c478bd9Sstevel@tonic-gate * there are messages in front of us ane we 564*7c478bd9Sstevel@tonic-gate * need to preserve message ordering) 565*7c478bd9Sstevel@tonic-gate * Therefore, put the message on the queue 566*7c478bd9Sstevel@tonic-gate * and call qdrain_syncq (must be done with 567*7c478bd9Sstevel@tonic-gate * the QLOCK held). 568*7c478bd9Sstevel@tonic-gate */ 569*7c478bd9Sstevel@tonic-gate STR_FTEVENT_MSG(mp, fqp, FTEV_PUTNEXT, 570*7c478bd9Sstevel@tonic-gate mp->b_rptr - mp->b_datap->db_base); 571*7c478bd9Sstevel@tonic-gate 572*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 573*7c478bd9Sstevel@tonic-gate /* 574*7c478bd9Sstevel@tonic-gate * These two values were in the original code for 575*7c478bd9Sstevel@tonic-gate * all syncq messages. This is unnecessary in 576*7c478bd9Sstevel@tonic-gate * the current implementation, but was retained 577*7c478bd9Sstevel@tonic-gate * in debug mode as it is usefull to know where 578*7c478bd9Sstevel@tonic-gate * problems occur. 579*7c478bd9Sstevel@tonic-gate */ 580*7c478bd9Sstevel@tonic-gate mp->b_queue = qp; 581*7c478bd9Sstevel@tonic-gate mp->b_prev = (mblk_t *)putproc; 582*7c478bd9Sstevel@tonic-gate #endif 583*7c478bd9Sstevel@tonic-gate SQPUT_MP(qp, mp); 584*7c478bd9Sstevel@tonic-gate qdrain_syncq(sq, qp); 585*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(QLOCK(qp))); 586*7c478bd9Sstevel@tonic-gate } 587*7c478bd9Sstevel@tonic-gate } 588*7c478bd9Sstevel@tonic-gate /* 589*7c478bd9Sstevel@tonic-gate * Before we release our claim, we need to see if any 590*7c478bd9Sstevel@tonic-gate * events were posted. If the syncq is SQ_EXCL && SQ_QUEUED, 591*7c478bd9Sstevel@tonic-gate * we were responsible for going exclusive and, therefore, 592*7c478bd9Sstevel@tonic-gate * are resposible for draining. 593*7c478bd9Sstevel@tonic-gate */ 594*7c478bd9Sstevel@tonic-gate if (sq->sq_flags & (SQ_EXCL)) { 595*7c478bd9Sstevel@tonic-gate drain_mask = 0; 596*7c478bd9Sstevel@tonic-gate } else { 597*7c478bd9Sstevel@tonic-gate drain_mask = SQ_QUEUED; 598*7c478bd9Sstevel@tonic-gate } 599*7c478bd9Sstevel@tonic-gate 600*7c478bd9Sstevel@tonic-gate if (sqciplock != NULL) { 601*7c478bd9Sstevel@tonic-gate mutex_enter(sqciplock); 602*7c478bd9Sstevel@tonic-gate flags = sq->sq_flags; 603*7c478bd9Sstevel@tonic-gate ASSERT(flags & SQ_CIPUT); 604*7c478bd9Sstevel@tonic-gate /* SQ_EXCL could have been set by qwriter_inner */ 605*7c478bd9Sstevel@tonic-gate if ((flags & (SQ_EXCL|SQ_TAIL)) || sq->sq_needexcl) { 606*7c478bd9Sstevel@tonic-gate /* 607*7c478bd9Sstevel@tonic-gate * we need SQLOCK to handle 608*7c478bd9Sstevel@tonic-gate * wakeups/drains/flags change. sqciplock 609*7c478bd9Sstevel@tonic-gate * is needed to decrement sqcipcount. 610*7c478bd9Sstevel@tonic-gate * SQLOCK has to be grabbed before sqciplock 611*7c478bd9Sstevel@tonic-gate * for lock ordering purposes. 612*7c478bd9Sstevel@tonic-gate * after sqcipcount is decremented some lock 613*7c478bd9Sstevel@tonic-gate * still needs to be held to make sure 614*7c478bd9Sstevel@tonic-gate * syncq won't get freed on us. 615*7c478bd9Sstevel@tonic-gate * 616*7c478bd9Sstevel@tonic-gate * To prevent deadlocks we try to grab SQLOCK and if it 617*7c478bd9Sstevel@tonic-gate * is held already we drop sqciplock, acquire SQLOCK and 618*7c478bd9Sstevel@tonic-gate * reacqwire sqciplock again. 619*7c478bd9Sstevel@tonic-gate */ 620*7c478bd9Sstevel@tonic-gate if (mutex_tryenter(SQLOCK(sq)) == 0) { 621*7c478bd9Sstevel@tonic-gate mutex_exit(sqciplock); 622*7c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 623*7c478bd9Sstevel@tonic-gate mutex_enter(sqciplock); 624*7c478bd9Sstevel@tonic-gate } 625*7c478bd9Sstevel@tonic-gate flags = sq->sq_flags; 626*7c478bd9Sstevel@tonic-gate ASSERT(*sqcipcount != 0); 627*7c478bd9Sstevel@tonic-gate (*sqcipcount)--; 628*7c478bd9Sstevel@tonic-gate mutex_exit(sqciplock); 629*7c478bd9Sstevel@tonic-gate } else { 630*7c478bd9Sstevel@tonic-gate ASSERT(*sqcipcount != 0); 631*7c478bd9Sstevel@tonic-gate (*sqcipcount)--; 632*7c478bd9Sstevel@tonic-gate mutex_exit(sqciplock); 633*7c478bd9Sstevel@tonic-gate TRACE_3(TR_FAC_STREAMS_FR, TR_PUTNEXT_END, 634*7c478bd9Sstevel@tonic-gate "putnext_end:(%p, %p, %p) done", qp, mp, sq); 635*7c478bd9Sstevel@tonic-gate return; 636*7c478bd9Sstevel@tonic-gate } 637*7c478bd9Sstevel@tonic-gate } else { 638*7c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 639*7c478bd9Sstevel@tonic-gate flags = sq->sq_flags; 640*7c478bd9Sstevel@tonic-gate ASSERT(sq->sq_count != 0); 641*7c478bd9Sstevel@tonic-gate sq->sq_count--; 642*7c478bd9Sstevel@tonic-gate } 643*7c478bd9Sstevel@tonic-gate if ((flags & (SQ_TAIL)) || sq->sq_needexcl) { 644*7c478bd9Sstevel@tonic-gate putnext_tail(sq, qp, (flags & ~drain_mask)); 645*7c478bd9Sstevel@tonic-gate /* 646*7c478bd9Sstevel@tonic-gate * The only purpose of this ASSERT is to preserve calling stack 647*7c478bd9Sstevel@tonic-gate * in DEBUG kernel. 648*7c478bd9Sstevel@tonic-gate */ 649*7c478bd9Sstevel@tonic-gate ASSERT(sq != NULL); 650*7c478bd9Sstevel@tonic-gate return; 651*7c478bd9Sstevel@tonic-gate } 652*7c478bd9Sstevel@tonic-gate ASSERT((sq->sq_flags & (SQ_EXCL|SQ_CIPUT)) || queued); 653*7c478bd9Sstevel@tonic-gate ASSERT((flags & (SQ_EXCL|SQ_CIPUT)) || queued); 654*7c478bd9Sstevel@tonic-gate /* 655*7c478bd9Sstevel@tonic-gate * Safe to always drop SQ_EXCL: 656*7c478bd9Sstevel@tonic-gate * Not SQ_CIPUT means we set SQ_EXCL above 657*7c478bd9Sstevel@tonic-gate * For SQ_CIPUT SQ_EXCL will only be set if the put 658*7c478bd9Sstevel@tonic-gate * procedure did a qwriter(INNER) in which case 659*7c478bd9Sstevel@tonic-gate * nobody else is in the inner perimeter and we 660*7c478bd9Sstevel@tonic-gate * are exiting. 661*7c478bd9Sstevel@tonic-gate * 662*7c478bd9Sstevel@tonic-gate * I would like to make the following assertion: 663*7c478bd9Sstevel@tonic-gate * 664*7c478bd9Sstevel@tonic-gate * ASSERT((flags & (SQ_EXCL|SQ_CIPUT)) != (SQ_EXCL|SQ_CIPUT) || 665*7c478bd9Sstevel@tonic-gate * sq->sq_count == 0); 666*7c478bd9Sstevel@tonic-gate * 667*7c478bd9Sstevel@tonic-gate * which indicates that if we are both putshared and exclusive, 668*7c478bd9Sstevel@tonic-gate * we became exclusive while executing the putproc, and the only 669*7c478bd9Sstevel@tonic-gate * claim on the syncq was the one we dropped a few lines above. 670*7c478bd9Sstevel@tonic-gate * But other threads that enter putnext while the syncq is exclusive 671*7c478bd9Sstevel@tonic-gate * need to make a claim as they may need to drop SQLOCK in the 672*7c478bd9Sstevel@tonic-gate * has_writers case to avoid deadlocks. If these threads are 673*7c478bd9Sstevel@tonic-gate * delayed or preempted, it is possible that the writer thread can 674*7c478bd9Sstevel@tonic-gate * find out that there are other claims making the (sq_count == 0) 675*7c478bd9Sstevel@tonic-gate * test invalid. 676*7c478bd9Sstevel@tonic-gate */ 677*7c478bd9Sstevel@tonic-gate 678*7c478bd9Sstevel@tonic-gate sq->sq_flags = flags & ~SQ_EXCL; 679*7c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 680*7c478bd9Sstevel@tonic-gate TRACE_3(TR_FAC_STREAMS_FR, TR_PUTNEXT_END, 681*7c478bd9Sstevel@tonic-gate "putnext_end:(%p, %p, %p) done", qp, mp, sq); 682*7c478bd9Sstevel@tonic-gate } 683