Museum

Home

Lab Overview

Retrotechnology Articles

Online Manuals

⇒ bufcall(D3) — UnixWare 2.01

Media Vault

Software Library

Restoration Projects

Artifacts Sought






       bufcall(D3)                                              bufcall(D3)


       NAME
             bufcall - call a function when a buffer becomes available

       SYNOPSIS
             #include <sys/types.h>
             #include <sys/stream.h>
             #include <sys/ddi.h>
             toid_t bufcall(uint_t size, int pri, void (*func)(), long arg);

          Arguments
            size
                Number of bytes in the buffer to be allocated (from the
                failed allocb(D3) request).

            pri
                Priority of the allocb allocation request.

            func
                Function or driver routine to be called when a buffer
                becomes available.

            arg
                Argument to the function to be called when a buffer becomes
                available.

       DESCRIPTION
             When a buffer allocation request fails, the function bufcall
             can be used to schedule the routine, func, to be called with
             the argument, arg, when a buffer of at least size bytes
             becomes available.  bufcall serves, in effect, as a timeout
             call of indeterminate length.

          Return Values
             On success, bufcall returns a non-zero value that identifies
             the scheduling request.  On failure, bufcall returns 0.

       USAGE
             When func runs, all interrupts from STREAMS devices will be
             blocked.  On multiprocessor systems, when func runs all
             interrupts from STREAMS devices will be blocked on the
             processor on which func is running.  func will have no user
             context and may not call any function that sleeps.

             Even when func is called, allocb can still fail if another
             module or driver had allocated the memory before func was able
             to call allocb.


                           Copyright 1994 Novell, Inc.               Page 1













      bufcall(D3)                                              bufcall(D3)


            The pri argument is a hint to the allocator indicating how
            badly the buffer is needed.  BPRI_LO should be used for normal
            data allocations.  BPRI_MED should be used for other non-
            critical allocations.  BPRI_HI should be used for allocations
            that absolutely must succeed, although success is not
            guaranteed.  Some implementations may choose to ignore this
            argument.

            The non-zero identifier returned by bufcall may be passed to
            unbufcall(D3) to cancel the request.

         Level
            Base or Interrupt.

         Synchronization Constraints
            Does not sleep.

            Driver-defined basic locks, read/write locks, and sleep locks
            may be held across calls to this function.

         Singlethreaded Example
            The purpose of this service routine [see srv(D2)] is to add a
            header to all M_DATA messages.  We assume only M_DATA messages
            are added to its queue.  Service routines must process all
            messages on their queues before returning, or arrange to be
            rescheduled.

            While there are messages to be processed (line 19), we check
            to see if we can send the message on in the stream.  If not,
            we put the message back on the queue (line 21) and return.
            The STREAMS flow control mechanism will re-enable us later
            when messages can be sent.  If canput(D3) succeeded, we try to
            allocate a buffer large enough to hold the header (line 24).
            If no buffer is available, the service routine must be
            rescheduled later, when a buffer is available.  We put the
            original message back on the queue (line 26) and use bufcall
            to attempt the rescheduling (lines 27 and 28).  If bufcall
            succeeds, we set the m_type field in the module's private data
            structure to BUFCALL.  If bufcall failed, we use timeout(D3)
            to reschedule us instead (line 30).  modcall will be called in
            about a half second [drv_usectohz(500000)].  When the
            rescheduling has been done, we return.

            When modcall runs, it will set the m_type field to zero,
            indicating that there is no outstanding request.  Then the
            queue's service routine is scheduled to run by calling


                          Copyright 1994 Novell, Inc.               Page 2













       bufcall(D3)                                              bufcall(D3)


             qenable(D3).

             If the buffer allocation is successful, we initialize the
             header (lines 37-39), make the message type M_PROTO (line 41),
             link the M_DATA message to it (line 42), and pass it on (line
             43).

             See unbufcall(D3) for the other half of this example.

              1  struct hdr {
              2    uint_t      h_size;
              3    int   h_version;
              4  };
              5  struct mod {
              6    long  m_id;
              7    char  m_type;
                   ...
              8  };
              9  #define TIMEOUT     1
             10  #define BUFCALL     2
                 ...
             11  modsrv(q)     /* assume only M_DATA messages enqueued here */
             12        queue_t *q;
             13  {
             14    mblk_t *bp;
             15    mblk_t *mp;
             16    struct hdr *hp;
             17    struct mod *modp;
             18    modp = (struct mod *)q->q_ptr;
             19    while ((mp = getq(q)) != NULL) {
             20          if (!canput(q->q_next)) {
             21                putbq(q, mp);
             22                return;
             23          }
             24          bp = allocb(sizeof(struct hdr), BPRI_MED);
             25          if (bp == NULL) {
             26                putbq(q, mp);
             27                modp->m_id = bufcall(sizeof(struct hdr), BPRI_MED, modcall,
             28                   (long)q);
             29                if (modp->m_id == 0) {
             30                   modp->m_id = timeout(modcall, (long)q, drv_usectohz(500000));
             31                   modp->m_type = TIMEOUT;
             32                } else {
             33                   modp->m_type = BUFCALL;
             34                }
             35                return;


                           Copyright 1994 Novell, Inc.               Page 3













      bufcall(D3)                                              bufcall(D3)


            36          }
            37          hp = (struct hdr *)bp->b_wptr;
            38          hp->h_size = msgdsize(mp);
            39          hp->h_version = 1;
            40          bp->b_wptr += sizeof(struct hdr);
            41          bp->b_datap->db_type = M_PROTO;
            42          bp->b_cont = mp;
            43          putnext(q, bp);
            44    }
            45  }
            46  modcall(q)
            47    queue_t *q;
            48  {
            49    struct mod *modp;
            50    modp = (struct mod *)q->q_ptr;
            51    modp->m_type = 0;
            52    qenable(q);
            53  }

         Multithreaded Example
            The purpose of this service routine [see srv(D2)] is to add a
            header to all M_DATA messages.  We assume only M_DATA messages
            are added to its queue.  Service routines must process all
            messages on their queues before returning, or arrange to be
            rescheduled.

            While there are messages to be processed (line 21), we check
            to see if we can send the message on in the stream.  If not,
            we put the message back on the queue (line 23) and return.
            The STREAMS flow control mechanism will re-enable us later
            when messages can be sent.  If canputnext(D3) succeeded, we
            try to allocate a buffer large enough to hold the header (line
            26).  If no buffer is available, the service routine must be
            rescheduled later, when a buffer is available.  We put the
            original message back on the queue (line 28), lock the private
            data structure, and use bufcall to attempt the rescheduling
            (lines 30 and 31).  If bufcall succeeds, we set the m_type
            field in the module's private data structure to BUFCALL.  If
            bufcall failed, we use itimeout(D3) to reschedule us instead
            (line 33).  modcall will be called in about a half second
            [drv_usectohz(500000)].  When the rescheduling has been done,
            we unlock the private data structure and return.

            When modcall runs, it will lock the private data structure and
            set the m_type field to zero, indicating that there is no
            outstanding request.  Then the data structure is unlocked and


                          Copyright 1994 Novell, Inc.               Page 4













       bufcall(D3)                                              bufcall(D3)


             the queue's service routine is scheduled to run by calling
             qenable(D3) (line 59).

             If the buffer allocation is successful, we initialize the
             header (lines 41-43), make the message type M_PROTO (line 45),
             link the M_DATA message to it (line 46), and pass it on (line
             47).

             See unbufcall(D3) for the other half of this example.
              1  struct hdr {
              2    uint_t      h_size;
              3    int   h_version;
              4  };
              5  struct mod {
              6    toid_t      m_id;
              7    char  m_type;
              8    lock_t      *m_lock;
                   . . .
              9  };
             10  #define TIMEOUT     1
             11  #define BUFCALL     2
                 . . .
             12  modsrv(q)     /* assume only M_DATA messages enqueued here */
             13        queue_t *q;
             14  {
             15    mblk_t *bp;
             16    mblk_t *mp;
             17    struct hdr *hp;
             18    struct mod *modp;
             19    pl_t pl;
             20    modp = (struct mod *)q->q_ptr;
             21    while ((mp = getq(q)) != NULL) {
             22          if (!canputnext(q)) {
             23                putbq(q, mp);
             24                return;
             25          }
             26          bp = allocb(sizeof(struct hdr), BPRI_MED);
             27          if (bp == NULL) {
             28                putbq(q, mp);
             29                pl = LOCK(modp->m_lock, plstr);
             30                modp->m_id = bufcall(sizeof(struct hdr), BPRI_MED, modcall,
             31                   (long)q);
             32                if (modp->m_id == 0) {
             33                   modp->m_id = itimeout(modcall, q, drv_usectohz(500000), plstr);
             34                   modp->m_type = TIMEOUT;
             35                } else {


                           Copyright 1994 Novell, Inc.               Page 5













      bufcall(D3)                                              bufcall(D3)


            36                   modp->m_type = BUFCALL;
            37                }
            38                UNLOCK(modp->m_lock, pl);
            39                return;
            40          }
            41          hp = (struct hdr *)bp->b_wptr;
            42          hp->h_size = msgdsize(mp);
            43          hp->h_version = 1;
            44          bp->b_wptr += sizeof(struct hdr);
            45          bp->b_datap->db_type = M_PROTO;
            46          bp->b_cont = mp;
            47          putnext(q, bp);
            48    }
            49  }
            50  modcall(q)
            51    queue_t *q;
            52  {
            53    struct mod *modp;
            54    pl_t pl;
            55    modp = (struct mod *)q->q_ptr;
            56    pl = LOCK(modp->m_lock, plstr);
            57    modp->m_type = 0;
            58    UNLOCK(modp->m_lock, pl);
            59    qenable(q);
            60  }

      REFERENCES
            allocb(D3), esballoc(D3), esbbcall(D3), itimeout(D3),
            timeout(D3), unbufcall(D3)

      NOTICES
         Portability
            All processors

         Applicability
            ddi: 1, 2, 3, 4, 5, 5mp, 6, 6mp, 7, 7mp

            The bufcall function is currently defined to return a toid_t
            data type.  In earlier releases, it returned an int.









                          Copyright 1994 Novell, Inc.               Page 6








Typewritten Software • bear@typewritten.org • Edmonds, WA 98026