bufcall(D3DK) —
.IX \f4bufcall\fP(D3DK)
NAME
bufcall − call a function when a buffer becomes available
SYNOPSIS
#include <sys/types.h>
#include <sys/stream.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(D3DK) request).
pri Priority of the allocb allocation request (BPRI_LO, BPRI_MED, BPRI_HI, or BPRI_CONSOLE).
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
bufcall serves as a timeout call of indeterminate length. When a buffer allocation request fails, 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.
When func runs, all interrupts from STREAMS devices will be blocked on the processor on which it is running. func will have no user context and may not call any function that sleeps.
RETURN VALUE
If successful, bufcall returns a non-zero value that identifies the scheduling request. This non-zero identifier may be passed to unbufcall(D3DK) to cancel the request. If any failure occurs, bufcall returns 0.
LEVEL
Base or Interrupt.
NOTES
Does not sleep.
Driver-defined basic locks, read/write locks, and sleep locks may be held across calls to this function.
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.
SEE ALSO
allocb(D3DK), esballoc(D3DK), esbbcall(D3DK), itimeout(D3DK), unbufcall(D3DK)
EXAMPLE
The purpose of this service routine [see srv(D2DK)] 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(D3DK) 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(D3DK) 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 the queue’s service routine is scheduled to run by calling qenable(D3DK) (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(D3DK) for the other half of this example.
1 struct hdr {
2uint_th_size;
3inth_version;
4 };
5 struct mod {
6toid_tm_id;
7charm_type;
8lock_t∗m_lock;
. . .
9 };
10 #define TIMEOUT1
11 #define BUFCALL2
. . .
12 modsrv(q)/∗ assume only M_DATA messages enqueued here ∗/
13 queue_t ∗q;
14 {
15mblk_t ∗bp;
16mblk_t ∗mp;
17struct hdr ∗hp;
18struct mod ∗modp;
19pl_t pl;
20modp = (struct mod ∗)q->q_ptr;
21while ((mp = getq(q)) != NULL) {
22if (!canputnext(q)) {
23putbq(q, mp);
24return;
25}
26bp = allocb(sizeof(struct hdr), BPRI_MED);
27if (bp == NULL) {
28putbq(q, mp);
29pl = LOCK(modp->m_lock, plstr);
30modp->m_id = bufcall(sizeof(struct hdr), BPRI_MED, modcall,
31 (long)q);
32if (modp->m_id == 0) {
33 modp->m_id = itimeout(modcall, q, drv_usectohz(500000), plstr);
34 modp->m_type = TIMEOUT;
35} else {
36 modp->m_type = BUFCALL;
37}
38UNLOCK(modp->m_lock, pl);
39return;
40}
41hp = (struct hdr ∗)bp->b_wptr;
42hp->h_size = msgdsize(mp);
43hp->h_version = 1;
44bp->b_wptr += sizeof(struct hdr);
45bp->b_datap->db_type = M_PROTO;
46bp->b_cont = mp;
47putnext(q, bp);
48}
49 }
50 modcall(q)
51queue_t ∗q;
52 {
53struct mod ∗modp;
54pl_t pl;
55modp = (struct mod ∗)q->q_ptr;
56pl = LOCK(modp->m_lock, plstr);
57modp->m_type = 0;
58UNLOCK(modp->m_lock, pl);
59qenable(q);
60 }
.IX \f4canputnext\fP(D3DK), example
.IX \f4putnext\fP(D3DK), example
.IX \f4putbq\fP(D3DK), example
.IX \f4allocb\fP(D3DK), example
.IX \f4qenable\fP(D3DK), example
.IX \f4itimeout\fP(D3DK), example
.IX \f4getq\fP(D3DK), example
.IX \f4msgdsize\fP(D3DK), example
.IX \f4bufcall\fP(D3DK), example
.IX \f4LOCK\fP(D3DK), example
.IX \f4UNLOCK\fP(D3DK), example
DDI/DKI — STREAMS