|
|
1.1 ! root 1: #define _DDI_DKI 1 ! 2: #define _SYSV4 1 ! 3: ! 4: /* ! 5: * This file contains various miscellaneous STREAMS library functions that ! 6: * have been moved into a file on their own. Mostly, this stuff deals with ! 7: * scheduling STREAMS service procedures, running STREAMS service procedures, ! 8: * invoking bufcall ()/esbbcall () events, and similar stuff. ! 9: */ ! 10: ! 11: #include <common/ccompat.h> ! 12: #include <kernel/strmlib.h> ! 13: #include <sys/debug.h> ! 14: #include <sys/types.h> ! 15: #include <sys/kmem.h> ! 16: #include <sys/stream.h> ! 17: ! 18: ! 19: /* ! 20: * Allocate and initialize a schedule. ! 21: * ! 22: * Callable only from base level. This function may sleep. ! 23: */ ! 24: ! 25: #if __USE_PROTO__ ! 26: ssched_t * (QSCHED_ALLOC) (void) ! 27: #else ! 28: ssched_t * ! 29: QSCHED_ALLOC __ARGS (()) ! 30: #endif ! 31: { ! 32: ssched_t * sched; ! 33: ! 34: if ((sched = (ssched_t *) kmem_alloc (sizeof (* sched), KM_SLEEP)) ! 35: != NULL) { ! 36: ! 37: if (SCHLOCK_INIT (sched, KM_SLEEP) == 0) { ! 38: ! 39: kmem_free (sched, sizeof (* sched)); ! 40: return NULL; ! 41: } ! 42: ! 43: sched->ss_head = sched->ss_tail = NULL; ! 44: } ! 45: ! 46: return sched; ! 47: } ! 48: ! 49: ! 50: /* ! 51: * Destroy a schedule. ! 52: * ! 53: * The schedule most not have any STREAMS queues threaded on it. ! 54: */ ! 55: ! 56: #if __USE_PROTO__ ! 57: void (QSCHED_FREE) (ssched_t * sched) ! 58: #else ! 59: void ! 60: QSCHED_FREE __ARGS ((sched)) ! 61: ssched_t * sched; ! 62: #endif ! 63: { ! 64: ASSERT (sched != NULL); ! 65: ASSERT (sched->ss_head == NULL && sched->ss_tail == NULL); ! 66: ! 67: SCHLOCK_DESTROY (sched); ! 68: ! 69: kmem_free (sched, sizeof (* sched)); ! 70: } ! 71: ! 72: ! 73: /* ! 74: * Remove a queue from a schedule. This function is available for modules and ! 75: * drivers to call. Note that STREAMS itself will only call this function at ! 76: * queue destruction time. ! 77: */ ! 78: ! 79: #if __USE_PROTO__ ! 80: void (QSCHED_UNSCHEDULE) (queue_t * q, ssched_t * sched) ! 81: #else ! 82: void ! 83: QSCHED_UNSCHEDULE __ARGS ((q, sched)) ! 84: queue_t * q; ! 85: ssched_t * sched; ! 86: #endif ! 87: { ! 88: pl_t lock_pl; ! 89: queue_t * scan; ! 90: queue_t * prev; ! 91: ! 92: ASSERT (sched != NULL); ! 93: QUEUE_TRACE (q, "QUEUE_UNSCHEDULE"); ! 94: ! 95: lock_pl = SCHLOCK_LOCK (sched, "QUEUE_UNSCHEDULE"); ! 96: ! 97: for (scan = sched->ss_head, prev = NULL ; scan != NULL ; ! 98: scan = (prev = scan)->q_link) { ! 99: ! 100: if (scan == q) { ! 101: ! 102: if (prev == NULL) ! 103: sched->ss_head = q->q_next; ! 104: else ! 105: prev->q_link = q->q_next; ! 106: ! 107: if (sched->ss_tail == q) ! 108: sched->ss_tail = prev; ! 109: break; ! 110: } ! 111: } ! 112: ! 113: SCHLOCK_UNLOCK (str_mem->sm_sched, lock_pl); ! 114: } ! 115: ! 116: ! 117: /* ! 118: * Dequeue and return the first stream in the schedule. ! 119: */ ! 120: ! 121: #if __USE_PROTO__ ! 122: queue_t * (QSCHED_GETFIRST) (ssched_t * sched) ! 123: #else ! 124: queue_t * ! 125: QSCHED_GETFIRST __ARGS ((sched)) ! 126: ssched_t * sched; ! 127: #endif ! 128: { ! 129: pl_t prev_pl; ! 130: queue_t * q; ! 131: ! 132: ASSERT (sched != NULL); ! 133: ! 134: prev_pl = SCHLOCK_LOCK (sched, "QSCHED_GETFIRST"); ! 135: ! 136: if ((q = sched->ss_head) != NULL) { ! 137: ! 138: if ((sched->ss_head = q->q_link) == NULL) ! 139: sched->ss_tail = NULL; ! 140: } ! 141: ! 142: SCHLOCK_UNLOCK (sched, prev_pl); ! 143: ! 144: return q; ! 145: } ! 146: ! 147: ! 148: /* ! 149: * Add a queue to a schedule. This function is available for use by modules ! 150: * and drivers. It is callable from base or interrupt level and does not ! 151: * sleep. ! 152: * ! 153: * The return value is 0 for success, and -1 if it is unable to schedule the ! 154: * queue. ! 155: */ ! 156: ! 157: #if __USE_PROTO__ ! 158: int (QSCHED_SCHEDULE) (queue_t * q, ssched_t * sched) ! 159: #else ! 160: int ! 161: QSCHED_SCHEDULE __ARGS ((q, sched)) ! 162: queue_t * q; ! 163: ssched_t * sched; ! 164: #endif ! 165: { ! 166: pl_t lock_pl; ! 167: ! 168: QUEUE_TRACE (q, "QSCHED_SCHEDULE"); ! 169: ! 170: /* ! 171: * Link this queue into the tail of the scheduling ! 172: * list after locking the scheduling list. ! 173: */ ! 174: ! 175: lock_pl = SCHLOCK_LOCK (sched, "QSCHED_SCHEDULE"); ! 176: ! 177: q->q_link = NULL; ! 178: ! 179: if (sched->ss_tail == NULL) ! 180: sched->ss_head = q; ! 181: else ! 182: sched->ss_tail->q_link = q; ! 183: ! 184: sched->ss_tail = q; ! 185: ! 186: SCHLOCK_UNLOCK (str_mem->sm_sched, lock_pl); ! 187: ! 188: ! 189: /* ! 190: * Under this implementation, it is not really possible for a request ! 191: * to fail, but because we are using STREAMS internal data here, we ! 192: * allow for a portable implementation that may fail. ! 193: */ ! 194: ! 195: return 0; ! 196: } ! 197: ! 198: ! 199: /* ! 200: * Code for checking which bufcall events to call, in a function by itself to ! 201: * keep things clear and maintainable. ! 202: * ! 203: * We take a snapshot of the available memory, then loop over the bufcall ()/ ! 204: * esbbcall () lists and give away memory until our notion of what the memory ! 205: * pool size ought to be drops to a level where there are cells we think we ! 206: * should hold off enabling... if we make that decision, we mark things so ! 207: * that next time through here we look again, then we exit. ! 208: */ ! 209: ! 210: #if __USE_PROTO__ ! 211: void (RUN_BUFCALLS) (void) ! 212: #else ! 213: void ! 214: RUN_BUFCALLS __ARGS (()) ! 215: #endif ! 216: { ! 217: size_t mem_level; ! 218: pl_t prev_pl; ! 219: sevent_t * runlist; ! 220: sevent_t * seventp; ! 221: int i; ! 222: ! 223: /* ! 224: * Take a snapshot of the amount of STREAMS memory that is in use, so ! 225: * we can parcel it out to the bufcall routines. We clear the bufcall ! 226: * defer flag now so that if STREAMS memory is made available after ! 227: * our snapshot we will be run again. ! 228: */ ! 229: ! 230: ATOMIC_STORE_UCHAR (ddi_global_data ()->dg_run_bufcalls, 0); ! 231: ! 232: mem_level = str_mem->sm_used; ! 233: runlist = NULL; ! 234: ! 235: for (i = N_PRI_LEVELS ; i -- > 0 ; ) { ! 236: selist_t * elistp; ! 237: unsigned long max = str_mem->sm_max [i]; ! 238: ! 239: elistp = & str_mem->sm_bcevents [i]; ! 240: ! 241: prev_pl = SELIST_LOCK (elistp); ! 242: ! 243: while ((seventp = elistp->sl_head) != NULL) { ! 244: /* ! 245: * If the amount of memory requested in this cell is ! 246: * enough to push the memory level over the top for ! 247: * this allocation priority, then give up. ! 248: */ ! 249: ! 250: if ((mem_level += seventp->se_size) > max) ! 251: goto give_up; ! 252: ! 253: /* ! 254: * Dequeue the event from the event list and add it to ! 255: * our work list. ! 256: */ ! 257: ! 258: elistp->sl_head = seventp->se_next; ! 259: ! 260: seventp->se_next = runlist; ! 261: runlist = seventp; ! 262: } ! 263: ! 264: #if _FIFO_BUFCALL ! 265: /* ! 266: * If we have drained all the events in this cell... ! 267: */ ! 268: ! 269: elistp->sl_tail = NULL; ! 270: #endif ! 271: ! 272: give_up: ! 273: SELIST_UNLOCK (elistp, prev_pl); ! 274: ! 275: if (seventp != NULL) ! 276: break; ! 277: } ! 278: ! 279: ! 280: /* ! 281: * Now use 'i' as a boolean to remember whether we have any ! 282: * outstanding event cells we though it better not to run. ! 283: */ ! 284: ! 285: i = seventp != NULL; ! 286: ! 287: ! 288: /* ! 289: * Now walk over our little work list... ! 290: */ ! 291: ! 292: while (runlist != NULL) { ! 293: ! 294: seventp = runlist; ! 295: runlist = seventp->se_next; ! 296: ! 297: prev_pl = splstr (); ! 298: ! 299: (* seventp->se_func) (seventp->se_arg); ! 300: ! 301: (void) splx (prev_pl); ! 302: ! 303: kmem_free (seventp, sizeof (* seventp)); ! 304: } ! 305: ! 306: ! 307: /* ! 308: * If we found anything worth running, try again after we have given ! 309: * the bufcall functions a chance to claim the memory that was free ! 310: * first time through. We queue another defer request so that we give ! 311: * a chance to other deferred routines. ! 312: */ ! 313: ! 314: if (i) ! 315: SCHEDULE_BUFCALLS (); ! 316: } ! 317: ! 318: ! 319: /* ! 320: * Streams scheduling routine, invoked before return to user level. Runs any ! 321: * service procedures that have been enabled, calls bufcall ()/esbbcall () ! 322: * events if memory is sitting around, and also wakes up processes sleeping ! 323: * in kmem_alloc ()/kmem_zalloc () for memory to become available. ! 324: */ ! 325: ! 326: #if __USE_PROTO__ ! 327: void (RUN_STREAMS) (void) ! 328: #else ! 329: void ! 330: RUN_STREAMS __ARGS (()) ! 331: #endif ! 332: { ! 333: queue_t * q; ! 334: ! 335: /* ! 336: * Before we start running through the queues that we need to service, ! 337: * turn off the "deferred" flag for this routine to avoid race ! 338: * conditions. ! 339: */ ! 340: ! 341: ATOMIC_STORE_UCHAR (ddi_global_data ()->dg_run_strsched, 0); ! 342: ! 343: while ((q = QSCHED_GETFIRST (str_mem->sm_sched)) != NULL) { ! 344: pl_t prev_pl; ! 345: ! 346: /* ! 347: * Before we run the service procedure, we must ensure ! 348: * that we are not going to re-enter the service ! 349: * routine. After that, we can turn off the 'enabled' ! 350: * flag. ! 351: */ ! 352: ! 353: prev_pl = QFREEZE_TRACE (q, "STREAMS_SCHEDULER"); ! 354: ! 355: if ((q->q_flag & QSRVACTIVE) != 0) { ! 356: /* ! 357: * Put the queue back and look for something ! 358: * else to do. ! 359: */ ! 360: ! 361: QUNFREEZE_TRACE (q, prev_pl); ! 362: QSCHED_SCHEDULE (q, str_mem->sm_sched); ! 363: ! 364: continue; ! 365: } ! 366: ! 367: q->q_flag = (q->q_flag & ~ QENAB) | QSRVACTIVE; ! 368: ! 369: if ((q->q_flag & QPROCSOFF) != 0) { ! 370: /* ! 371: * The service procedure of this queue has ! 372: * been disabled, so we leave things alone. ! 373: */ ! 374: ! 375: goto srvdone; ! 376: } ! 377: ! 378: q->q_active ++; ! 379: ! 380: QUNFREEZE_TRACE (q, prev_pl); ! 381: ! 382: ! 383: (* q->q_qinfo->qi_srvp) (q); ! 384: ! 385: ! 386: prev_pl = QFREEZE_TRACE (q, "STREAMS_SCHEDULER"); ! 387: ! 388: q->q_flag &= ~ QSRVACTIVE; ! 389: ! 390: if (-- q->q_active == 0 && (q->q_flag & QPROCSOFF) != 0) { ! 391: /* ! 392: * Wake up the qprocoffs () procedure waiting ! 393: * for us to go exit. ! 394: */ ! 395: ! 396: (void) LOCK (str_mem->sm_proc_lock, plstr); ! 397: SV_BROADCAST (str_mem->sm_proc_sv, 0); ! 398: UNLOCK (str_mem->sm_proc_lock, plstr); ! 399: } ! 400: srvdone: ! 401: QUNFREEZE_TRACE (q, prev_pl); ! 402: } ! 403: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.