Annotation of coherent/f/usr/include/kernel/strmlib.h, revision 1.1

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__ */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.