|
|
1.1 ! root 1: #ifndef __KERNEL_STRMLIB_H__ ! 2: #define __KERNEL_STRMLIB_H__ ! 3: ! 4: /* ! 5: * This ^^^^^^^^^^^^^^^^^ symbol is used in the DDI/DKI header <sys/ddi.h> to ! 6: * determine which #undef directives it is required to perform, on the basis ! 7: * that it should avoid touching namespaces unless they have been reserved ! 8: * by the inclusion of a header which reserves such classes of names. ! 9: */ ! 10: ! 11: /* ! 12: * This file contains definitions that are be used for the implementation of ! 13: * the STREAMS standard library routines and scheduling code. Some details ! 14: * of the interfaces between STREAMS and the rest of the system will also ! 15: * be dealt with here so as to insulate the STREAMS implementation from the ! 16: * details of that interface. ! 17: * ! 18: * Note that as the contents of this header are for private, system internal ! 19: * use only, names do not begin with underscores. ! 20: */ ! 21: ! 22: /* ! 23: *-IMPORTS: ! 24: * <common/ccompat.h> ! 25: * __EXTERN_C_BEGIN__ ! 26: * __EXTERN_C_END__ ! 27: * __PROTO () ! 28: * <common/xdebug.h> ! 29: * __LOCAL__ ! 30: * <common/__size.h> ! 31: * __size_t ! 32: * <common/__clock.h> ! 33: * __clock_t ! 34: * <common/__pid.h> ! 35: * __pid_t ! 36: * <kernel/st_alloc.h> ! 37: * _ST_HEAP_CONTROL ! 38: * <kernel/defer.h> ! 39: * defer_int_any () ! 40: * <sys/ksynch.h> ! 41: * lock_t ! 42: * sv_t ! 43: * <sys/uio.h> ! 44: * uio_t ! 45: */ ! 46: ! 47: #include <common/ccompat.h> ! 48: #include <common/xdebug.h> ! 49: #include <common/__size.h> ! 50: #include <common/__clock.h> ! 51: #include <common/__pid.h> ! 52: #include <kernel/st_alloc.h> ! 53: #include <kernel/defer.h> ! 54: #include <sys/inline.h> ! 55: #include <sys/ksynch.h> ! 56: #include <sys/uio.h> ! 57: ! 58: #include <common/_stream.h> ! 59: #include <kernel/ddi_lock.h> ! 60: #include <kernel/ddi_glob.h> ! 61: ! 62: /* ! 63: * In order to be able to declare prototypes that refer to structures that are ! 64: * declared in other headers, we supply incomplete declarations at top-level ! 65: * to avoid some scoping problems. ! 66: */ ! 67: ! 68: struct stroptions; ! 69: struct strbuf; ! 70: ! 71: ! 72: /* ! 73: * In onder for freezestr () to work as defined in the Multiprocessor DDI/DKI, ! 74: * it cannot simply be implemented in terms of the high-level locking ! 75: * operations defined in <sys/ksynch.h> (the reason being that it is specified ! 76: * as raising the processor priority level, whereas the "pl" parameter to the ! 77: * high-level locking functions is specified as setting the level, with a ! 78: * caution that it not cause the level to be lowered). ! 79: * ! 80: * Stream queue freezing cannot really be implemented in terms of high-level ! 81: * basic locks because of the hierarchy mechanism; the relative priority of ! 82: * stream head locks is determined by relative position in a stream so that ! 83: * following the "q_next" member yields increasing (virtual) hierarchy values, ! 84: * with the additional constraint that a given context may only hold a lock on ! 85: * one side of a stream at a time. ! 86: */ ! 87: ! 88: #define SFREEZE_INIT(q) ((void) ATOMIC_CLEAR_UCHAR ((q)->q_locked)) ! 89: #define SFREEZE_DESTROY(q) ((void) 0) ! 90: #define SFREEZE_LOCK(q,name) TEST_AND_SET_LOCK ((q)->q_locked, plstr, \ ! 91: (name)) ! 92: #define SFREEZE_UNLOCK(q,pl) (ATOMIC_CLEAR_UCHAR ((q)->q_locked), \ ! 93: (void) splx (pl)) ! 94: #define SFREEZE_ASSERT_FROZEN(q) ASSERT (ATOMIC_FETCH_UCHAR ((q)->q_locked)) ! 95: ! 96: ! 97: /* ! 98: * The implementation of allocb () and freeb () deals in terms of "triples" ! 99: * consisting of an mblk_t, a dblk_t, and the actual data being managed. ! 100: * (Of course, under esballoc () the data belongs to another subsystem, but ! 101: * such a double should also be managed by the same system). ! 102: * ! 103: * Be aware that changing the definition of any of these things may ! 104: * invalidate assumptions made by the code in allocb (), freeb (), dupb () ! 105: * and esballoc (). ! 106: */ ! 107: ! 108: /* ! 109: * Various ways to map between the components of a triple. ! 110: */ ! 111: ! 112: #define MB_TO_DB(mp) ((dblk_t *) (mp + 1)) ! 113: #define DB_TO_MB(db) (((mblk_t *) db) - 1) ! 114: #define DB_TO_DATA(db) ((unsigned char *) (db + 1)) ! 115: #define DATA_TO_DB(d) (((dblk_t *) d)) - 1) ! 116: ! 117: ! 118: /* ! 119: * Some useful predicates for determining whether various items are actually ! 120: * parts of triples or not, since there are exceptional cases where the ! 121: * individual elements of a triple have been scattered to the four winds. ! 122: * ! 123: * Note that the SET_MB_TRIPLE () and SET_MB_FREE () exist as a pair, since ! 124: * they only relate to message blocks that are part of a triple. ! 125: * SET_MB_TRIPLE () is used when a message block is instantiated, and ! 126: * SET_MB_FREE () is used when a message block is deallocated but the rest ! 127: * of the triple is still in use. ! 128: */ ! 129: ! 130: #define IS_DB_USER_DATA(db) (db->db_base != DB_TO_DATA (db)) ! 131: /* ! 132: * Test to see whether the ! 133: * data referenced by this ! 134: * block is user-controlled. ! 135: */ ! 136: ! 137: #define IS_TRIPLE_TOGETHER(mp) (mp->b_datap == MB_TO_DB (mp)) ! 138: /* ! 139: * Test to see whether the ! 140: * data block referenced by ! 141: * this message block forms ! 142: * part of the same triple. ! 143: */ ! 144: ! 145: #define SET_MB_TRIPLE(mp) (void) ((mp)->b_flags =\ ! 146: ((mp)->b_flags | MSGTRIPLE) & ~ MSGFREE) ! 147: /* ! 148: * Mark the message block as ! 149: * part of a triple. ! 150: */ ! 151: ! 152: #define IS_MB_TRIPLE(mp) (((mp)->b_flags & MSGTRIPLE) != 0) ! 153: /* ! 154: * Test whether the message ! 155: * block is part of a triple ! 156: * or is a floating block. ! 157: */ ! 158: ! 159: #define SET_MB_FREE(mp) (void) ((mp)->b_flags |= MSGFREE) ! 160: /* ! 161: * Indicate that the message ! 162: * block is no longer in ! 163: * use. Only for message ! 164: * blocks in triples. ! 165: */ ! 166: ! 167: #define IS_MB_FREE(mp) ((mp->b_flags & MSGFREE) != 0) ! 168: /* ! 169: * Test whether the message ! 170: * block is free or not. ! 171: */ ! 172: ! 173: /* ! 174: * STREAMS Local extension: scheduling ! 175: */ ! 176: ! 177: /* ! 178: * The methods used in the multiplexing examples in the STREAMS Programmer's ! 179: * Guide for System V Release 2 are quite inefficient. The following general ! 180: * STREAMS queue scheduling structures and routines were defined in a visible ! 181: * manner since ! 182: * ! 183: * (i) It served to better-document the way in which queues are serviced ! 184: * within this STREAMS implementation, ! 185: * ! 186: * (ii) Multiplexing drivers (and device drivers which multiplex several ! 187: * minor numbers on a single I/O bus, such as an Ethernet or SCSI ! 188: * driver) need effcient mechanisms for managing multiple request ! 189: * channels, ! 190: * ! 191: * (iii) It allows drivers to leverage the multiprocessor locking that is ! 192: * built into these primitives. ! 193: * ! 194: * Note that allowing drivers access to this facility causes a significant ! 195: * departure from the standard version of STREAMS, but that driver use of the ! 196: * macros and data structures below permits other implementations. ! 197: * ! 198: * As this system is used internally by this STREAMS implementation, it can ! 199: * use the "q_link" member of a queue to hold a link to the next STREAM on ! 200: * a schedule. In addition, some "q_flag" bits can be used to control ! 201: * whether or not a queue is currently threaded on any schedule. A portable ! 202: * implementation that does not depend on any reserved parts of STREAMS ! 203: * data structures may not use these fields, and so may operate under a ! 204: * different set of constraints. However, since in this case the drivers and ! 205: * STREAMS itself share common scheduling code, the following restrictions ! 206: * must be observed: ! 207: * ! 208: * (i) A queue may be requested to be scheduled more than once with no ! 209: * effect. If a queue is requested to be scheduled on different ! 210: * schedules, then this is probably an error, most likely to occur ! 211: * if you define both a STREAMS service routine and a schedule for ! 212: * a driver queue; this should not be done under the common scheme. ! 213: * ! 214: * (ii) A queue which has noenable () set on it will still be scheduled. ! 215: * The manner in which qenable ()/noenable () work has no bearing on ! 216: * this mechanism. ! 217: * ! 218: * (iii) Schedules should only be created or destroyed with the schedule ! 219: * allocation/deallocation routines in order to guarantee that the ! 220: * schedule is multi-processor addressable and is the correct size for ! 221: * the selected run-time environment. ! 222: * ! 223: * (iv) When a driver is closed, the queue must not be on any schedule in ! 224: * order to prevent list corruption and the dire effects that can ! 225: * result from such corruption. A portable implementation of scheduling ! 226: * has no way to do this automatically for the driver since the ! 227: * close () call is managed by STREAMS. ! 228: * ! 229: * Note that in this common implementation, conditions (i), (iii), and (iv) ! 230: * can be checked by the scheduling system if compiled such that debugging ! 231: * code is inserted. ! 232: */ ! 233: ! 234: /* ! 235: * STREAMS scheduler private per-schedule global data structure. ! 236: */ ! 237: ! 238: struct __streams_schedule { ! 239: queue_t * ss_head; /* head of list of scheduled queues */ ! 240: queue_t * ss_tail; /* tail of list of scheduled queues */ ! 241: ! 242: lock_t * ss_locked; /* lock for schedule */ ! 243: }; ! 244: ! 245: ! 246: extern lkinfo_t __stream_schedule_lkinfo; ! 247: ! 248: #define SCHLOCK_INIT(s,flag) \ ! 249: ((s)->ss_locked = LOCK_ALLOC (stream_schedule_hierarchy, plstr, \ ! 250: & __stream_schedule_lkinfo, (flag))) ! 251: ! 252: #define SCHLOCK_DESTROY(s) LOCK_DEALLOC ((s)->ss_locked) ! 253: ! 254: #define SCHLOCK_LOCK(s,n) LOCK ((s)->ss_locked, plstr) ! 255: ! 256: #define SCHLOCK_UNLOCK(s,p) UNLOCK ((s)->ss_locked, p) ! 257: ! 258: #define SCHLOCK_ASSERT_LOCKED(s) \ ! 259: ASSERT (TRYLOCK ((s)->ss_locked, plstr) == invpl) ! 260: ! 261: #define SCHED_INIT(s,flag) ((s)->ss_head = (s)->ss_tail = NULL, \ ! 262: SCHLOCK_INIT (s, flag)) ! 263: ! 264: ! 265: /* ! 266: * I use these everywhere that I know which queue side I've got. These ! 267: * macros duplicate the old-style RD () and WR () functionality, which has ! 268: * been changed along the path from System V Release 3.2 to System V Release ! 269: * 4 Multi-Processor. When compiling under the DDI/DKI, these macros are also ! 270: * converted to functions. ! 271: */ ! 272: ! 273: #define W(q) ((q) + 1) ! 274: #define R(q) ((q) - 1) ! 275: ! 276: ! 277: /* ! 278: * A utility function, for use with STRMEM_ALLOC (), to calculate the size ! 279: * required for a message triple with "n" bytes of associated data buffer. ! 280: */ ! 281: ! 282: #define MSGB_SIZE(n) ((n) + sizeof (mblk_t) + sizeof (dblk_t)) ! 283: ! 284: ! 285: /* ! 286: * The following data type is used to hold registration information for the ! 287: * SIGPOLL signal. Every process that registers for SIGPOLL signals allocates ! 288: * one of these structures and threads it on the stream head. ! 289: */ ! 290: ! 291: typedef struct sigpoll sigpoll_t; ! 292: ! 293: ! 294: /* ! 295: * The following is the internal structure (an "event cell" in STREAMS) ! 296: * used by the bufcall ()/esbbcall () mechanism to record the necessary ! 297: * information for calling the user back. ! 298: * ! 299: * Note that the real System V bufcall ()/esbbcall () takes a a pointer to ! 300: * a function with undefined parameters, yet also accepts a parameter which ! 301: * it will then pass on to the callback. The only way to implement this at ! 302: * all portably is to use some version of the ISO <stdarg.h> mechanism to ! 303: * allow bufcall () to take any argument in it's "natural" form and then ! 304: * pass a maximum-sized chunk of stack into the callback in order to capture ! 305: * all of the information that the client wanted to pass. ! 306: * ! 307: * Of course, doing this is opening a wide door to all kinds of problems, ! 308: * since while there are some sleazy ways to restrict the size of the extra ! 309: * argument to something reasonable, there is no way that we can make sure ! 310: * that the shapes of the argument and the callback parameter really do ! 311: * match (eg, the callback takes a long but bufcall () is given an int). ! 312: * ! 313: * Of course, this is all no worse than the situation AT&T have under the ! 314: * DDI/DKI, where bufcall () is required to take the callback parameter as ! 315: * a "long" and clients assume that pointers have the same shape as longs ! 316: * (if you look at the example in bufcall (D3DK) that is exactly what A&T ! 317: * seem to be suggesting - blech). ! 318: * ! 319: * There is no entirely satisfactory way to get around this evil in plain C, ! 320: * although we can get at least a partial solution through supplying a range ! 321: * of supplementary definitions that (at least in an ISO environment) ensure ! 322: * that the function argument types and argument types will be coerced to ! 323: * something reasonable. ! 324: * ! 325: * Event management is made a little more complex by the availability of the ! 326: * unbufcall () procedure, which requires us to assign a numeric ID code to ! 327: * each event cell. It would be nice if this ID code also included some kind ! 328: * of generation field, and mapped instantly to the desired value. ! 329: * ! 330: * Note that this is exactly the same problem faced by the timeout () routine ! 331: * in implementing untimeout (), and there are numerous possible solutions, ! 332: * each of which maximizes some desirable property at the cost of losing some ! 333: * other property. ! 334: */ ! 335: ! 336: #define _TOID_MEMBER 1 ! 337: ! 338: typedef void (* se_funcptr_t) __PROTO ((long _arg)); ! 339: ! 340: typedef struct __stream_event sevent_t; ! 341: ! 342: struct __stream_event { ! 343: sevent_t * se_next; /* next event in chain */ ! 344: sevent_t * se_prev; /* previous event in chain */ ! 345: long se_arg; /* argument for function */ ! 346: se_funcptr_t se_func; /* function to call */ ! 347: unsigned int se_size; /* optional size information */ ! 348: #if _TOID_MEMBER ! 349: toid_t se_id; /* timeout id for item */ ! 350: #endif ! 351: }; ! 352: ! 353: ! 354: /* ! 355: * Of course, we have to thread the above events on a list. We'll create a ! 356: * structure for this to abstract the details of the locking scheme we'll use ! 357: * for maintaining the consistency of the event lists. ! 358: * ! 359: * We store a generator for the timeout ID codes in the list header so that ! 360: * the ID generation step can be protected by the same lock as the list ! 361: * manipulation code. This means that at initialisation time each list header ! 362: * should have the initial ID code set to its number and that the increment ! 363: * value used to step between codes is one greater than the total number of ! 364: * list headers (so that code 0 never appears). ! 365: * ! 366: * We have a wide range of possible policies for managing event cells. We need ! 367: * to get some performance data on each to make a final decision. ! 368: */ ! 369: ! 370: #define _FIFO_BUFCALL 1 ! 371: ! 372: typedef struct __stream_event_list selist_t; ! 373: ! 374: struct __stream_event_list { ! 375: lock_t * sl_locked; ! 376: sevent_t * sl_head; ! 377: #if _FIFO_BUFCALL ! 378: sevent_t * sl_tail; ! 379: #endif ! 380: #if _TOID_MEMBER ! 381: toid_t sl_id; ! 382: #endif ! 383: }; ! 384: ! 385: ! 386: extern lkinfo_t __stream_event_lkinfo; ! 387: ! 388: #define SELIST_INIT(s,flag) \ ! 389: ((s)->sl_head = NULL, \ ! 390: (s)->sl_locked = LOCK_ALLOC (stream_event_hierarchy, plstr, \ ! 391: & __stream_event_lkinfo, (flag))) ! 392: ! 393: #define SELIST_DESTROY(s) LOCK_DEALLOC ((s)->sl_locked) ! 394: ! 395: #define SELIST_LOCK(s) LOCK ((s)->sl_locked, plstr) ! 396: ! 397: #define SELIST_UNLOCK(s,pl) UNLOCK ((s)->sl_locked, (pl)) ! 398: ! 399: #define SELIST_ASSERT_LOCKED(s) \ ! 400: ASSERT (TRYLOCK ((s)->sl_locked, plstr) == invpl) ! 401: ! 402: ! 403: /* ! 404: * Some handy requirements for timeout ID generation. We have to define these ! 405: * numbers such that each list above generates a non-overlapping sequence that ! 406: * overflows into the same sequence, eg. ! 407: * 1, k + 1, 2k + 1, ... ik + 1, 1, ... ! 408: * 2, k + 2, 2k + 2, ... ik + 2, 2, ... ! 409: * ! 410: * Since each list generates a distinct and identifiable sequence we can map ! 411: * from the ID to the list in one step, which somewhat ameliorates the cost ! 412: * of having to search the list to find the given event. ! 413: */ ! 414: ! 415: #define TOID_INCREMENT (N_PRI_LEVELS + 1) ! 416: #define TOID_MODULUS (TOID_MAX - TOID_MAX % TOID_INCREMENT) ! 417: #define TOID_TO_PRI(id) ((id) % TOID_INCREMENT - 1) ! 418: ! 419: ! 420: /* ! 421: * Watermark control structures: ! 422: * ! 423: * We record here the amount of memory held by each allocation band and the ! 424: * maximum amount we will permit it to hold. In addition, we record a thread ! 425: * of structures used by bufcall () and esbbcall () to record information ! 426: * for callbacks to drivers when memory becomes available. ! 427: */ ! 428: /* ! 429: * A note on bufcall ()/esbbcall () structures; ! 430: * ! 431: * I am not able to conceive of a comprehensive strategy for dealing with ! 432: * these things that works well under all circumstances. For now, it seems ! 433: * that keeping a few around in preallocated event cells is a good idea for ! 434: * when we run out of memory. However, as long as possible the system will ! 435: * always attempt to satisfy a request for an event cell with a newly ! 436: * allocated cell, since we expect the usual reason for being unable to ! 437: * satisfy a request is that memory is merely fragmented rather than fully ! 438: * occupied. ! 439: * ! 440: * Of course, allocating bufcall cells within the heap may increase the ! 441: * level of fragmentation - which is why we prefer to allocate them from ! 442: * the "long-term" heap (and indeed, why we have two heaps at all). ! 443: */ ! 444: ! 445: #define N_PRI_LEVELS 3 /* ! 446: * Number of buffer priority levels ! 447: */ ! 448: #define MAP_PRI_LEVEL(p) p /* ! 449: * Map from BPRI_xxx to index. ! 450: */ ! 451: ! 452: /* #define SPLIT_STREAMS_MEMORY */ /* ! 453: * Control whether there are separate ! 454: * arenas for messages and other ! 455: * allocations. ! 456: */ ! 457: ! 458: /* ! 459: * We keep several lists of stream heads according to the category of the ! 460: * stream; device, pipe, and possibly FIFO. Various general operations require ! 461: * iterating over several of the lists, and so we define an array of list ! 462: * head pointers to simplify things since we don't have the C++ "pointer to ! 463: * member" types and operations available. ! 464: */ ! 465: ! 466: typedef struct __stream_head shead_t; ! 467: ! 468: typedef enum slist_id { ! 469: DEV_SLIST, ! 470: PIPE_SLIST, ! 471: SLIST_MAX ! 472: } slist_id_t; ! 473: ! 474: typedef int muxid_t; ! 475: ! 476: ! 477: /* ! 478: * This structure grew to its present form before the <kernel/ddi_glob.h> ! 479: * header took shape. Most of it should eventually be moved there, with ! 480: * appropriate thought given to what should be fixed and what should be ! 481: * variable allocations. ! 482: */ ! 483: ! 484: ! 485: struct streams_mem { ! 486: atomic_uchar_t sm_init; /* primitive lock for startup */ ! 487: ! 488: __size_t sm_used; /* memory used in the message heap */ ! 489: __size_t sm_max [N_PRI_LEVELS]; ! 490: /* ! 491: * Maximum memory we let a level use ! 492: */ ! 493: ! 494: toid_t sm_bcid; /* id generator for bufcall events */ ! 495: selist_t sm_bcevents [N_PRI_LEVELS]; ! 496: /* ! 497: * Bufcall event linked-list head. ! 498: */ ! 499: ssched_t sm_sched [1]; /* List of enabled queues. */ ! 500: ! 501: lock_t * sm_seq_lock; /* Lock sequence number registers. */ ! 502: unsigned long sm_err_seq; /* error log sequence number */ ! 503: unsigned long sm_trc_seq; /* trace log sequence number */ ! 504: unsigned long sm_con_seq; /* console log sequence number */ ! 505: ! 506: queue_t * sm_log_rq; /* STREAMS logger device */ ! 507: ! 508: lock_t * sm_proc_lock; /* Basic lock for qprocsoff (). */ ! 509: sv_t * sm_proc_sv; /* ! 510: * Synchronization variable for ! 511: * qprocsoff (). ! 512: */ ! 513: queue_t * sm_log_drvr; /* Log-driver read side. */ ! 514: ! 515: rwlock_t * sm_head_lock; /* Lock for stream head list */ ! 516: shead_t * sm_streams [SLIST_MAX]; ! 517: /* Chains of stream heads */ ! 518: ! 519: __size_t sm_maxctlsize; /* max. size of control message */ ! 520: __size_t sm_maxdatasize; /* max. size of data message part */ ! 521: ! 522: ! 523: /*---------- Locked by sm_msg_lock ------------*/ ! 524: lock_t * sm_msg_lock; /* basic lock for message heap */ ! 525: _ST_HEAP_CONTROL_P sm_msg_heap; /* Memory heap for STREAMS messages */ ! 526: sv_t * sm_msg_sv; /* ! 527: * synchronization variable for ! 528: * waiting for free memory. ! 529: */ ! 530: __size_t sm_msg_needed; /* Level of free memory required */ ! 531: ! 532: #ifdef SPLIT_STREAMS_MEMORY ! 533: /*---------- Locked by sm_other_lock ------------*/ ! 534: ! 535: lock_t * sm_other_lock; /* basic lock for "other" heap */ ! 536: ! 537: _ST_HEAP_CONTROL_P sm_other_heap;/* Memory heap for long-term info */ ! 538: ! 539: sv_t * sm_other_sv; /* ! 540: * synchronization variable for ! 541: * waiting for free memory. ! 542: */ ! 543: __size_t sm_other_needed;/* Level of free memory required */ ! 544: #else ! 545: # define sm_other_heap sm_msg_heap ! 546: # define sm_other_lock sm_msg_lock ! 547: # define sm_other_sv sm_msg_sv ! 548: # define sm_other_needed sm_msg_needed ! 549: #endif ! 550: }; ! 551: ! 552: ! 553: /* ! 554: * These should be the standard priorities to be used with the locks for ! 555: * controlling access to the various memory pools. ! 556: */ ! 557: ! 558: #ifdef SPLIT_STREAMS_MEMORY ! 559: ! 560: # define str_msg_pl plstr ! 561: # define str_other_pl plhi ! 562: ! 563: #else ! 564: ! 565: # define str_msg_pl plhi ! 566: # define str_other_pl plhi ! 567: ! 568: #endif ! 569: ! 570: ! 571: /* ! 572: * When someone thinks it might be a good idea to see about running some of ! 573: * the bufcall routines, we defer a routine to deal with the checking. A ! 574: * global flag bit protects ! 575: */ ! 576: ! 577: #define SCHEDULE_BUFCALLS() \ ! 578: (ATOMIC_FETCH_AND_STORE_UCHAR (ddi_global_data ()->dg_run_bufcalls, 1) \ ! 579: == 1 ? (void) 0 : (void) defer_int_any (RUN_BUFCALLS)) ! 580: ! 581: ! 582: /* ! 583: * If all allocations are coming from the same pool, non-message allocations ! 584: * need to be counted in with the allocation-priority information. ! 585: * ! 586: * The "other" pool (which will really be the message pool) should be locked ! 587: * when these functions are called. ! 588: */ ! 589: ! 590: #ifdef SPLIT_STREAMS_MEMORY ! 591: ! 592: # define OTHER_ALLOCED(size) ! 593: # define OTHER_FREED(size) ! 594: ! 595: #else ! 596: ! 597: # define OTHER_ALLOCED(size) (void) (str_mem->sm_used += size) ! 598: # define OTHER_FREED(size) ((void) (str_mem->sm_used -= size), \ ! 599: SCHEDULE_BUFCALLS ()) ! 600: ! 601: #endif ! 602: ! 603: ! 604: /* ! 605: * We need access to a global instance of the above for managing STREAMS ! 606: * memory in a consistent manner. ! 607: */ ! 608: ! 609: extern struct streams_mem str_mem []; ! 610: ! 611: ! 612: /* ! 613: * Category flags for the sh_lock_mask member. This is a collection of flag ! 614: * bits which correspond to operations on the "sh_wait_sv" synchronization ! 615: * variable. ! 616: */ ! 617: ! 618: typedef enum category { ! 619: SH_NONE = 0, /* use for paranoid checking */ ! 620: SH_OPENCLOSE = 1, ! 621: SH_IOCTL_LOCK = 2, ! 622: SH_READ_LOCK = 4, /* NOT NORMALLY USED */ ! 623: SH_WRITE_LOCK = 8, /* NOT NORMALLY USED */ ! 624: SH_PEEK_LOCK = 16, ! 625: ! 626: SH_LOCK_MASK = 31, /* Mask for lock bits */ ! 627: ! 628: ! 629: SH_READ_WAIT = 32, ! 630: SH_WRITE_WAIT = 64, ! 631: SH_IOCTL_WAIT = 128, ! 632: SH_DRAIN_WAIT = 256, ! 633: SH_PEEK_WAIT = 512, ! 634: ! 635: SH_WAIT_MASK = 992, /* Mask for wait bits */ ! 636: ! 637: ! 638: /* ! 639: * Not a lock mask; just use the extra flag space. ! 640: */ ! 641: ! 642: SH_TIMEFLAG = 8192 ! 643: } cat_t; ! 644: ! 645: ! 646: /* ! 647: * Stream head control structure. ! 648: * ! 649: * Be careful with locking the stream head; for many operations, it may be ! 650: * sufficient to freeze the stream head. ! 651: */ ! 652: ! 653: struct __stream_head { ! 654: n_dev_t sh_dev; /* key for lookup */ ! 655: shead_t * sh_next; /* next stream head on chain */ ! 656: ! 657: queue_t * sh_head; /* read queue of stream head */ ! 658: struct streamtab ! 659: * sh_tab; /* initialisation data for driver */ ! 660: ! 661: __clock_t sh_cltime; /* time to wait for close to drain */ ! 662: ! 663: struct pollhead ! 664: * sh_pollhead; /* for polling support */ ! 665: ! 666: pid_t sh_pgrp; /* foreground TTY process group */ ! 667: __VOID__ * sh_controller; /* reference to controlling process */ ! 668: ! 669: int sh_rerrcode; /* error code from M_ERROR */ ! 670: int sh_werrcode; /* error code from M_ERROR */ ! 671: ! 672: unsigned short sh_flags; /* miscellaneous flags */ ! 673: ! 674: short sh_readopt; /* read options */ ! 675: short sh_wropt; /* write options */ ! 676: ! 677: unsigned short sh_wroff; /* write offset */ ! 678: ! 679: sigpoll_t * sh_sigs; /* processes registered for SIGPOLL */ ! 680: ! 681: toid_t sh_read_bufcall;/* ID for read bufcall () */ ! 682: ! 683: shead_t * sh_linked; /* head of stream we are linked to */ ! 684: muxid_t sh_muxid; /* our ID below that stream */ ! 685: ! 686: ! 687: lock_t * sh_basic_lockp; /* */ ! 688: ! 689: /*---- For process-level locking and timeout operations ----*/ ! 690: ! 691: sv_t * sh_wait_sv; /* for process lock operations */ ! 692: ! 693: int sh_lock_mask; /* which categories are locked */ ! 694: ! 695: short sh_ref_count; /* references to stream memory */ ! 696: short sh_open_count; /* successful open count */ ! 697: short sh_attach_count;/* attachments to stream */ ! 698: short sh_lock_count; /* processes queued or locked */ ! 699: short sh_time_count; /* count of timeout checks */ ! 700: ! 701: __clock_t sh_timeout_tick;/* current soonest timeout */ ! 702: toid_t sh_timeout_id; /* ID of current active timeout */ ! 703: ! 704: int sh_ioc_seq; /* ioctl () sequence number */ ! 705: mblk_t * sh_ioc_msg; /* ioctl () messages */ ! 706: }; ! 707: ! 708: ! 709: /* ! 710: * A collection of functions for dealing with the stream head basic lock. ! 711: */ ! 712: ! 713: #define SHEAD_LOCK(sheadp) LOCK ((sheadp)->sh_basic_lockp, plstr) ! 714: #define SHEAD_UNLOCK(sheadp,pl) UNLOCK ((sheadp)->sh_basic_lockp, pl) ! 715: #define SHEAD_ASSERT_LOCKED(sheadp) \ ! 716: ASSERT ((sheadp) != NULL && \ ! 717: TRYLOCK ((sheadp)->sh_basic_lockp, plstr) == invpl) ! 718: ! 719: ! 720: /* ! 721: * Masks for use with the "sh_flags" member. ! 722: */ ! 723: ! 724: enum { ! 725: SH_READMSG = 0x0001, /* generate M_READ messages */ ! 726: SH_NDELAY = 0x0002, /* non-STREAMS O_NDELAY semantics */ ! 727: SH_TTY = 0x0004, /* stream is acting as a tty */ ! 728: SH_TOSTOP = 0x0008, /* job control on background writes */ ! 729: ! 730: ! 731: SH_HANGUP = 0x0010, /* stream has been hung up */ ! 732: ! 733: SH_PLINK = 0x0020, /* stream is permanently linked */ ! 734: ! 735: /* ! 736: * Permanent flags set when the stream is created. We do not need a ! 737: * flag to indicate a pipe, because pipes have a NULL "sh_tab" entry ! 738: * to mark them. ! 739: */ ! 740: ! 741: SH_MASTER = 0x0100, /* master end of stream pipe */ ! 742: ! 743: ! 744: /* ! 745: * This flag enables serialization of reads and writes. This is a ! 746: * local, experimental extension to STREAMS. ! 747: */ ! 748: ! 749: SH_RWLOCKING = 0x0200 ! 750: }; ! 751: ! 752: ! 753: /* ! 754: * For stream pipes there is a master/slave relationship between the stream ! 755: * heads at each end. The following macros define some handy relationships ! 756: * between them to allow quick mapping from one to another. ! 757: */ ! 758: ! 759: #define SHEAD_M2SLAVE(m) ((m) + 1) ! 760: #define SHEAD_SLAVE2M(s) ((s) - 1) ! 761: #define SHEAD_MASTER(sheadp) (((sheadp)->sh_flags & SH_MASTER) == 0 ? \ ! 762: SHEAD_SLAVE2M (sheadp) : (sheadp)) ! 763: #define SHEAD_OTHER(sheadp) (((sheadp)->sh_flags & SH_MASTER) == 0 ? \ ! 764: SHEAD_SLAVE2M (sheadp) : \ ! 765: SHEAD_M2SLAVE (sheadp)) ! 766: ! 767: #define SHEAD_IS_PIPE(sheadp) ((sheadp)->sh_tab == NULL) ! 768: ! 769: #define SHEAD_HANGUP(sheadp) (((sheadp)->sh_flags & SH_HANGUP) != 0) ! 770: ! 771: #define SHEAD_READMSG(sheadp) (((sheadp)->sh_flags & SH_READMSG) != 0) ! 772: ! 773: ! 774: /* ! 775: * For working in with the abstract filesystem layer, we define a format for ! 776: * our opaque information. ! 777: */ ! 778: ! 779: typedef struct { ! 780: shead_t * sheadp; ! 781: } scookie_t; ! 782: ! 783: ! 784: ! 785: __EXTERN_C_BEGIN__ ! 786: ! 787: ssched_t * QSCHED_ALLOC __PROTO ((void)); ! 788: void SSCHED_FREE __PROTO ((ssched_t * _sched)); ! 789: int QSCHED_SCHEDULE __PROTO ((queue_t * _q, ssched_t * _sched)); ! 790: void QSCHED_UNSCHEDULE ! 791: __PROTO ((queue_t * _q, ssched_t * _sched)); ! 792: queue_t * QSCHED_GETFIRST __PROTO ((ssched_t * _sched)); ! 793: ! 794: pl_t QFREEZE_TRACE __PROTO ((queue_t * _q, ! 795: __CONST__ char * _name)); ! 796: void QFROZEN_TRACE __PROTO ((queue_t * _q, ! 797: __CONST__ char * _name)); ! 798: void QUEUE_TRACE __PROTO ((queue_t * _q, ! 799: __CONST__ char * _name)); ! 800: void QUNFREEZE_TRACE __PROTO ((queue_t * _q, pl_t _pl)); ! 801: ! 802: void QUEUE_BACKENAB __PROTO ((queue_t * _q)); ! 803: queue_t * QUEUE_NEXT __PROTO ((queue_t * _q)); ! 804: ! 805: mblk_t * STRMEM_ALLOC __PROTO ((__size_t _size, int _pri, ! 806: int _flag)); ! 807: void STRMEM_FREE __PROTO ((mblk_t * _bp, __size_t _size)); ! 808: ! 809: mblk_t * MSGB_ALLOC __PROTO ((__size_t _size, int _pri, ! 810: int _flag)); ! 811: ! 812: void SHEAD_WAKE __PROTO ((shead_t * _sheadp, cat_t _flag)); ! 813: void SHEAD_SIGNAL __PROTO ((shead_t * _sheadp, uchar_t _sig)); ! 814: int SHEAD_SRDOPT __PROTO ((shead_t * _sheadp, int _flag)); ! 815: void QBAND_SETOPT __PROTO ((queue_t * _q, ! 816: struct stroptions * _so)); ! 817: ! 818: qband_t * QUEUE_BAND __PROTO ((queue_t * _q, uchar_t _pri)); ! 819: qband_t * QBAND_PREV __PROTO ((queue_t * _q, qband_t * _qbandp)); ! 820: ! 821: void RUN_BUFCALLS __PROTO ((void)); ! 822: void RUN_STREAMS __PROTO ((void)); ! 823: ! 824: shead_t * SHEAD_FIND __PROTO ((n_dev_t _dev, slist_id_t _id)); ! 825: ! 826: int STREAMS_OPEN __PROTO ((n_dev_t * _devp, ! 827: struct streamtab * _stabp, ! 828: int _mode, cred_t * _credp)); ! 829: int STREAMS_CLOSE __PROTO ((shead_t * _sheadp, int _mode, ! 830: cred_t * _credp)); ! 831: ! 832: int STREAMS_READ __PROTO ((shead_t * _sheadp, uio_t * _uiop)); ! 833: int STREAMS_WRITE __PROTO ((shead_t * _sheadp, uio_t * _uiop)); ! 834: int STREAMS_IOCTL __PROTO ((shead_t * _sheadp, int _cmd, ! 835: _VOID * _arg, int _mode, ! 836: cred_t * _credp, int * _rvalp)); ! 837: ! 838: int STREAMS_CHPOLL __PROTO ((shead_t * _sheadp, short _events, ! 839: int _anyyet, short * _reventsp, ! 840: struct pollhead ** _phpp)); ! 841: ! 842: int STREAMS_GETPMSG __PROTO ((shead_t * _sheadp, ! 843: struct strbuf * _ctlbuf, ! 844: struct strbuf * _databuf, ! 845: int * _bandp, int * _flagsp, ! 846: int _mode, int * _rvalp)); ! 847: int STREAMS_PUTPMSG __PROTO ((shead_t * _sheadp, ! 848: struct strbuf * _ctlbuf, ! 849: struct strbuf * _databuf, int _band, ! 850: int _flags, int _mode, ! 851: int * _rvalp)); ! 852: ! 853: __EXTERN_C_END__ ! 854: ! 855: ! 856: /* ! 857: * This internal definition is the dual to QFREEZE_TRACE (), being the ! 858: * internal implementation of unfreezestr (). ! 859: */ ! 860: ! 861: #define QUNFREEZE_TRACE(q,pl) SFREEZE_UNLOCK (q, pl) ! 862: ! 863: ! 864: /* ! 865: * Dealing with queue priority bands can be a little tricky; in particular, ! 866: * the definition of the linked-list structure of priority bands has some ! 867: * characteristics that may be unsuitable for some implementations. ! 868: * Specifically, the "qband" structure apparently is designed to function as ! 869: * a member of a singly-linked list rooted in the "queue" structure. This is ! 870: * flexible, but if there are several priority bands the time spent in ! 871: * dereferencing the link pointers might outweigh any extra cost involved in ! 872: * keeping the "band" structures in a vector [While the allocation cost is ! 873: * neglible in terms of time, there is a potentially high cost in terms of ! 874: * increasing the likelihood of a failure to allocate a band structure]. ! 875: * ! 876: * The following internal functions have been defined to abstract away the ! 877: * details of how band structures are accessed from the queue, allowing a ! 878: * more time-efficient vector scheme to be used, or even a hybrid scheme ! 879: * where vectors are preferred but a linked-list fallback is available. ! 880: * ! 881: * The SVR4 DDI/DKI used to document the band structure, but that structure is ! 882: * no longer documented as of the SVR4 MP DDI/DKI. ! 883: */ ! 884: ! 885: #define VECTOR_BANDS ! 886: #define VECTOR_BANDS_TEST /* test mode for VECTOR_BANDS */ ! 887: ! 888: #ifdef VECTOR_BANDS ! 889: ! 890: #define QUEUE_BAND(q,pri) ((pri) > (q)->q_nband ? NULL : \ ! 891: & (q)->q_bandp [pri - 1]) ! 892: ! 893: #define QBAND_PREV(q,bandp) ((bandp) > (q)->q_bandp ? (bandp) - 1 : NULL) ! 894: ! 895: #endif /* defined (VECTOR_BANDS) */ ! 896: ! 897: ! 898: #endif /* ! __KERNEL_STRMLIB_H__ */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.