HPlogo STREAMS/UX for the HP 9000 Reference Manual > Chapter 6 Debugging STREAMS/UX Modules and Drivers

STREAMS/UX Debugging Tool

» 

Technical documentation

Complete book in PDF

 » Table of Contents

 » Index

HP-UX provides the strdb tool for examining STREAMS/UX data structures in the kernel. strdb is an interactive tool. You run the strdb program, and then enter commands to see data structures. This section describes strdb commands and shows examples of using strdb to find STREAMS/UX driver problems. The strdb man page summarizes strdb commands.

Running strdb

The syntax for the strdb command is:

strdb [vmunix_executable_file_name][vmunix_core_file_name]]

STREAMS/UX programmers can run strdb to look at snapshots of STREAMS/UX data structures in the kernel while HP-UX is running. Also, programmers can run strdb to look at STREAMS/UX data structures in a vmunix core file. To see STREAMS/UX data structures while the system is running, enter:

strdb

Sometimes the system is booted using a different kernel than /stand/vmunix, for example /vmunix.prev. In this case, run strdb by entering:

strdb /vmunix.prev

To look at STREAMS/UX data structures in a core file, pass the name of the hp-ux program and core files to strdb. For example, if the program and core files have the paths /var/adm/vmunix.0 and /var/adm/vmcore.0, enter:

strdb /var/adm/vmunix.0 /var/adm/vmcore.0

strdb Commands

After invoking strdb, you can enter commands to look at STREAMS/UX data structures. strdb runs in two modes, primary and STREAMS/UX subsystem. Each mode provides different commands.

Primary mode commands change the characteristics of the strdb session. For example, one command turns on logging to a file. Primary mode commands also allow you to navigate through STREAMS/UX data structures. When strdb starts up, you are in primary mode. You switch to STREAMS/UX subsystem mode by entering the :S command.

STREAMS/UX subsystem mode commands report what STREAMS/UX are configured and active on the system. Also, the qh command allows you to begin examining a particular stream's queues. This command displays a selected stream head read queue. In addition, it puts you into primary mode so that you can use the primary mode navigation commands to traverse the rest of that stream's queues. All the commands for both modes are listed later in this chapter.

In a typical strdb session, you might do the following:

  1. Start strdb (you are in primary mode).

  2. Execute the :S command to enter STREAMS/UX subsystem mode.

  3. Use STREAMS/UX subsystem mode commands to find the active stream you want to examine.

  4. Execute the qh command to display the selected stream head read queue. This puts you in primary mode.

  5. Enter primary mode navigation keys to display fields in the stream head read queue, and traverse the rest of that stream's queues.

STREAMS/UX Subsystem Commands

When you first enter strdb, strdb prints a message saying that you have not yet specified a stream to display. You can enter the :S command to get into the STREAMS/UX subsystem mode. strdb will display the following help menu.

STREAMS subsystem help commands
? - show this help menu
h - show this help menu
la 'name' - list all active STREAMS on device 'name'
ll 'name' 'minor' - list all drivers linked under the STREAMS
driver 'name' and minor number 'minor'
lm 'name' 'minor' - list all modules pushed on STREAMS device
'name'and whose minor number is 'minor'
lp 'name' 'minor' - list all drivers persistently linked under
the STREAMS device 'name' and minor number
'minor'
q - quit the STREAMS subsystem commands
qc 'driver' 'file' - print 'driver' read / write side qcount to
'file'
qh 'name' 'minor' - display STREAM head queue structure
for device 'name' and minor number 'minor'
s [m | d] - Option d lists all the STREAMS drivers
configured in the system. Option m lists
all the modules configured in the system
v - print version of STREAMS structures
displayed

The ?, h, q, v, s, la, lm, ll, lp, qc, and qh commands are available in subsystem mode. To execute these commands, enter the command at the ":" prompt. The commands help you find the stream that you want to examine. The commands are described below.

? and h Commands

Enter the ? or h command to see the help menu for STREAMS/UX subsystem mode. strdb prints the text shown below.

?

STREAMS subsystem help commands
? - show this help menu
h - show this help menu
la 'name' - list all active STREAMS on device 'name'
ll 'name' 'minor' - list all drivers linked under the STREAMS
driver 'name' and minor number 'minor'
lm 'name' 'minor' - list all modules pushed on STREAMS device
'name'
and whose minor number is 'minor'
lp 'name' 'minor' - list all drivers persistently linked under
the STREAMS device 'name' and minor number
'minor'
q - quit the STREAMS subsystem commands
qc 'driver' 'file' - print 'driver' read / write side qcount to
file
qh 'name' 'minor' - display STREAM head queue structure for
device 'name' and minor number 'minor'
s [m | d] - Option d lists all the STREAMS drivers
configured in the system. Option m lists
all the modules configured in the system
v - print version of STREAMS structures
displayed

q Command

Enter the q command to exit STREAMS/UX subsystem mode and enter primary mode. This is shown below.

    q
No current structure S:0

v Command

Enter the v command to display the version of STREAMS/UX data structures. This version should always be Release V 4.0. An example is shown below.

   v

STREAMS Version based on Release V 4.0

s Command

Enter the s [m|d] command to see the STREAMS/UX modules and drivers configured into the system. These are the modules and drivers included in the multiuser S800 file or the workstation dfile. Specify either m to see the modules or d to see the drivers. Examples are shown below.

s m

List of MODULES

timod
tirdwr
lmodb
lmode
lmodt
lmodr
lmodc
sc
bufcall

s d

List of DRIVERS

clone MAJOR = 72
strlog MAJOR = 73
sad MAJOR = 74
lo MAJOR = 75
tmx MAJOR = 77
tidg MAJOR = 78
tivc MAJOR = 79
loop MAJOR = 114
sp MAJOR = 115
test_wel MAJOR = 130

la Command

Enter the la command to see a list of opened streams for a driver. Also, enter the name of the driver. This name can be obtained from s command output. An example is shown below.

la tivc

tivc MAJOR = 79
ACTIVE Minor 0x00002f Stream head RQ = 0x676a00
ACTIVE Minor 0x00000f Stream head RQ = 0x663300
ACTIVE Minor 0x00000e Stream head RQ = 0x6a5900
ACTIVE Minor 0x00002e Stream head RQ = 0x71f800
ACTIVE Minor 0x00004e Stream head RQ = 0x6ccf00
ACTIVE Minor 0x00000d Stream head RQ = 0x67b300
ACTIVE Minor 0x00004d Stream head RQ = 0x73c700
ACTIVE Minor 0x00002d Stream head RQ = 0x728800
ACTIVE Minor 0x00004c Stream head RQ = 0x74f600
ACTIVE Minor 0x00000c Stream head RQ = 0x68d100
ACTIVE Minor 0x00002b Stream head RQ = 0x730a00

lm Command

Enter the lm command to see a list of the modules pushed onto a driver. You must specify the driver name and the minor number. The minor number can be obtained from the la command output. An example is shown below.

lm tivc 47

STREAM Head
timod
Driver tivc

ll Command

Enter the ll command to see a list of drivers linked under a multiplexor. You must enter the multiplexor name and the minor number. The multiplexor name can be obtained from the s output. The minor number is from the la output. An example is shown below.

ll tmx 0

lo MAJOR = 75 minor = 2
lo MAJOR = 75 minor = 1
lo MAJOR = 75 minor = 0

lp Command

Enter the lp command to see a list of drivers persistently linked under a multiplexor. You must enter the multiplexor name and the minor number. An example is shown below.

lp tmx 1

lo MAJOR = 75 minor = 2
lo MAJOR = 75 minor = 1
lo MAJOR = 75 minor = 0

qc Command

Enter the qc command to display the q_count field of a driver's read and write queues. The q_count field contains the number of bytes of data in the messages on the queue. The command will show the q_count values for all the opened streams of the requested driver. You must enter the driver name and the name of a file to contain the q_count values. strdb will create the specified file and write the q_count values into it. An example is shown below.

qc tmx stat

<< exit from strdb >>

%more stat
MINOR = 5
WQ = 0x40026760, WQ_count = 0, RQ = 0x40026760, RQ_count = 4214
WQ = 0x40026760, WQ_count = 0, RQ = 0x40026760, RQ_count = 0
MINOR = 4
WQ = 0x40026760, WQ_count = 0, RQ = 0x40026760, RQ_count = 842
WQ = 0x40026760, WQ_count = 0, RQ = 0x40026760, RQ_count = 0
MINOR = 1
WQ = 0x40026760, WQ_count = 0, RQ = 0x40026760, RQ_count = 930
WQ = 0x40026760, WQ_count = 0, RQ = 0x40026760, RQ_count = 0
MINOR = 0
WQ = 0x40026760, WQ_count = 0, RQ = 0x40026760, RQ_count = 0
WQ = 0x40026760, WQ_count = 0, RQ = 0x40026760, RQ_count = 0
MINOR = 3
WQ = 0x40026760, WQ_count = 0, RQ = 0x40026760, RQ_count = 3970
WQ = 0x40026760, WQ_count = 0, RQ = 0x40026760, RQ_count = 0
MINOR = 2
WQ = 0x40026760, WQ_count = 0, RQ = 0x40026760, RQ_count = 1300
WQ = 0x40026760, WQ_count = 0, RQ = 0x40026760, RQ_count = 0

qh Command

Enter the qh command to see a stream head read queue. Enter the driver name and minor number to specify the stream head read queue to display. An example is shown below. When strdb prints the stream head read queue, you are put in primary mode. This lets you enter navigation commands to look at data structures pointed to by fields in the queue. These navigation commands are described below under "Primary Commands."

qh tmx 0

struct queue 0x584300 S:1

q_qinfo = 0x2944f0 q_pad1[2] = 00
q_first = 0x0 q_other = 0x584374
q_last = 0x0
q_next = 0x0
q_link = 0x0
q_ptr = 0x5f8500
q_count = 0
q_flag = 0x1029
QREADR
QWANTR
QUSE
QSYNCH
q_minpsz = 0
q_maxpsz = -1
q_hiwat = 0x200
q_lowat = 0x100
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00

Primary Commands

strdb provides two types of primary mode commands. One kind is used to navigate through data structures. The other kind changes the characteristics of the strdb session.

Data Structure Navigation Commands

When you enter the qh command, strdb prints the stream head read queue and puts you in primary mode. You can enter navigation commands to look at data structures pointed to by fields in the queue. Note that primary mode does not prompt you for commands; you just enter the command keys. You do not need to enter a carriage return with navigation commands. In the example below, a ? is entered to see which fields strdb can format. strdb prints the commands for formatting these fields. A carriage return will clear the help screen and redisplay the stream head read queue. In the example below, the m key is entered to see the message block pointed to by q_first. Next, a ? is entered to see which message block fields strdb can format.

qh tmx 1

struct queue 0x21f7600 S:1

q_qinfo = 0x1f7924 q_pad1[2] = 00
q_first = 0x2156780 q_other = 0x21f7600
q_last = 0x2185800
q_next = 0x0
q_link = 0x0
q_ptr = 0x267be8
q_count = 22518
q_flag = 0x1120
QUSE
QOLD
QSYNCH
q_minpsz = 0
q_maxpsz = -1
q_hiwat = 0x200
q_lowat = 0x100
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00

?

navigation for structure queue
'i' = q_qinfo (qinit)
'm' = q_first (msgb)
'z' = q_last (msgb)
'n' = q_next (queue)
'l' = q_link (queue)
'b' = q_bandp (qband)
'o' = q_other (queue)

-- Hit any key to continue --

<carriage return>

struct queue 0x21f7600 S:1

q_qinfo = 0x1f7924 q_pad1[2] = 00
q_first = 0x2156780 q_other = 0x21f7600
q_last = 0x2185800
q_next = 0x0
q_link = 0x0
q_ptr = 0x267be8
q_count = 22518
q_flag = 0x1120
QUSE
QOLD
QSYNCH
q_minpsz = 0
q_maxpsz = -1
q_hiwat = 0x200
q_lowat = 0x100
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00

m

struct msgb 0x2156780 S:2

b_next = 0x204ac00
b_prev = 0x0
b_cont = 0x21fb700
b_rptr = 0x2242bf2
b_wptr = 0x2242bf2
b_datap = 0x0
b_band = 0
b_pad1 = 00
b_flag = 0x0
b_pad2 = 0

?

navigation for structure msgb
'n' = b_next (msgb)
'p' = b_prev (msgb)
'm' = b_rptr (b_rptr)
'c' = b_cont (msgb)
'd' = b_datap (datab)

-- Hit any key to continue --

strdb provides different navigation commands for each data structure it formats. The navigation commands for all the data structures are shown below.

Queue Navigation

'i'      = q_qinfo (qinit)
'm' = q_first (msgb)
'z' = q_last (msgb)
'n' = q_next (queue)
'l' = q_link (queue)
'b' = q_bandp (qband)
'o' = q_other (queue)

Qinit Navigation

'i'      = qi_minfo (module_info)
's' = qi_mstat (module_stat)

Message Block Navigation

'n'      = b_next (msgb)
'p' = b_prev (msgb)
'm' = b_rptr (b_rptr)
'c' = b_cont (msgb)
'd' = b_datap (datab)

Data Block Navigation

'd'      = db_f (a__datab) 

Queue Band Navigation

'n'      = qb_next (qband) 
'f' = qb_first (msgb)
'l' = qb_last (msgb)

Navigation Examples

The following information includes more navigation command examples. The CTRL-P, CTRL-T, :m, CTRL-U, :b, and :x commands, which are used in conjunction with the navigation commands, are shown with examples.

You can enter ? to see what navigation keys are available.

qh tmx 0

struct queue 0x21f7b00 S:1

q_qinfo = 0x1f7a18 q_pad1[2] = 00
q_first = 0x0 q_other = 0x21f7b74
q_last = 0x0
q_next = 0x0
q_link = 0x0
q_ptr = 0x21f7a00
q_count = 0
q_flag = 0x1029
QREADR
QWANTR
QUSE
QSYNCH
q_minpsz = 0
q_maxpsz = -1
q_hiwat = 0x200
q_lowat = 0x100
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00

?

navigation for structure queue
'i' = q_qinfo (qinit)
'm' = q_first (msgb)
'z' = q_last (msgb)
'n' = q_next (queue)
'l' = q_link (queue)
'b' = q_bandp (qband)
'o' = q_other (queue)

-- Hit any key to continue --

After typing a key to continue, you can enter any of the keys shown in the help text. For example, if you enter o, the stream head write queue will be displayed. This is shown below.

o

struct queue 0x21f7b74 S:2

q_qinfo = 0x1f7a34 q_pad1[2] = 00
q_first = 0x0 q_other = 0x21f7b00
q_last = 0x0
q_next = 0x21f7674
q_link = 0x0
q_ptr = 0x21f7a00
q_count = 0
q_flag = 0x102a
QNOENB
QWANTR
QUSE
QSYNCH
q_minpsz = 0
q_maxpsz = -1
q_hiwat = 0x2800
q_lowat = 0x400
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00

At this point you can enter n to see the next write queue on the stream. Note that strdb provides the same navigation keys for each queue structure. Therefore, you can enter the same keys for the stream head write queue as for the stream head read queue. An example of entering the n key is shown below.

n

struct queue 0x21f7674 S:3

q_qinfo = 0x1f7924 q_pad1[2] = 00
q_first = 0x2156780 q_other = 0x21f7600
q_last = 0x2185800
q_next = 0x0
q_link = 0x0
q_ptr = 0x0029cc48
q_count = 22518
q_flag = 0x1120
QUSE
QOLD
QSYNCH
q_minpsz = 0
q_maxpsz = -1
q_hiwat = 0x8000
q_lowat = 0x4000
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00

This queue contains a non-zero q_first pointer. The m navigation key can be used to look at the messages on the queue. This is shown below.

m

struct msgb 0x2156780 S:4

b_next = 0x204ac00
b_prev = 0x0
b_cont = 0x21fb700
b_rptr = 0x2242bf2
b_wptr = 0x2242bf2
b_datap = 0x0
b_band = 0
b_pad1 = 00
b_flag = 0x0
b_pad2 = 0

The m key displays the first message on the queue. The ? command shows the navigation queues available for the message block data structure.

?

navigation for structure msgb
'n' = b_next (msgb)
'p' = b_prev (msgb)
'm' = b_rptr (b_rptr)
'c' = b_cont (msgb)
'd' = b_datap (datab)

-- Hit any key to continue --

The n key shows the next message on the queue.

n

struct msgb 0x204ac00 S:5

b_next = 0x21f4b00
b_prev = 0x218ee00
b_cont = 0x2198080
b_rptr = 0x223dc00
b_wptr = 0x223ddc3
b_datap = 0x204ac40
b_band = 0
b_pad1 = 00
b_flag = 0x0
b_pad2 = 0

The m key shows the data associated with this message block.

m

struct msgb 0x204ac00 Message data at 0x0223dc00 S:6

0x0223dc00 : 01491800 76777879 7a616263 64656667 |
.I..vwxyzabcdefg
0x0223dc10 : 68696a6b 6c6d6e6f 70717273 74757677 | hijklmnopqrstuvw
0x0223dc20 : 78797a61 62636465 66676869 6a6b6c6d | xyzabcdefghijklm
0x0223dc30 : 6e6f7071 72737475 76777879 7a616263 | nopqrstuvwxyzabc
0x0223dc40 : 64656667 68696a6b 6c6d6e6f 70717273 | defghijklmnopqrs
0x0223dc50 : 74757677 78797a61 62636465 66676869 | tuvwxyzabcdefghi
0x0223dc60 : 6a6b6c6d 6e6f7071 72737475 76777879 | jklmnopqrstuvwxy
0x0223dc70 : 7a616263 64656667 68696a6b 6c6d6e6f | zabcdefghijklmno
0x0223dc80 : 70717273 74757677 78797a61 62636465 | pqrstuvwxyzabcde
0x0223dc90 : 66676869 6a6b6c6d 6e6f7071 72737475 | fghijklmnopqrstu
0x0223dca0 : 76777879 7a616263 64656667 68696a6b | vwxyzabcdefghijk
0x0223dcb0 : 6c6d6e6f 70717273 74757677 78797a61 | lmnopqrstuvwxyza
0x0223dcc0 : 62636465 66676869 6a6b6c6d 6e6f7071 | bcdefghijklmnopq
0x0223dcd0 : 72737475 76777879 7a616263 64656667 | rstuvwxyzabcdefg
0x0223dce0 : 68696a6b 6c6d6e6f 70717273 74757677 | hijklmnopqrstuvw
0x0223dcf0 : 78797a61 62636465 66676869 6a6b6c6d | xyzabcdefghijklm
0x0223dd00 : 6e6f7071 72737475 76777879 7a616263 | nopqrstuvwxyzabc
0x0223dd10 : 64656667 68696a6b 6c6d6e6f 70717273 | defghijklmnopqrs
0x0223dd20 : 74757677 78797a61 62636465 66676869 | tuvwxyzabcdefghi
0x0223dd30 : 6a6b6c6d 6e6f7071 72737475 76777879 | jklmnopqrstuvwxy
Type c for more data
Any other key will quit this display

You can continue to type the c key to see the rest of the data. Enter a key other than c to stop examining data.

Note that each time strdb displays a data structure, it pushes it onto a stack. strdb saves structures on a stack so you can re-examine them later. strdb increments and displays the stack depth. The depth appears in the upper right hand corner of the screen as "S:depth." In the current example, the message data is on the top of the stack, and the depth is 6.

At this point, you may want to see the next message in the queue. To do this, enter a key other than c to stop examining data. Then you can enter the primary mode command CTRL-P to pop the message data and get back to the message block for the data. This is shown below.

<< press a key besides c >>

^P

struct msgb 0x204ac00 S:5

b_next = 0x21f4b00
b_prev = 0x218ee00
b_cont = 0x2198080
b_rptr = 0x223dc00
b_wptr = 0x223ddc3
b_datap = 0x204ac40
b_band = 0
b_pad1 = 00
b_flag = 0x0
b_pad2 = 0

In this example, you could have returned to the message block by entering CTRL-T to transpose the top two stack entries instead of popping. This has the advantage that the message data is still on the stack in case you want to look at it later. The last example is redone below using CTRL-T. Notice that the stack depth for the message block is 6 after transposing instead of 5 after popping.

^T

struct msgb 0x204ac00 S:6

b_next = 0x21f4b00
b_prev = 0x218ee00
b_cont = 0x2198080
b_rptr = 0x223dc00
b_wptr = 0x223ddc3
b_datap = 0x204ac40
b_band = 0
b_pad1 = 00
b_flag = 0x0
b_pad2 = 0

Besides popping the top of the stack or transposing stack entries, you can pop back to a mark. Enter the :m command to set a mark on the data structure stack. Later, enter CTRL-U to pop back to the structure with the mark. For example, suppose that in the previous examples :m was entered after strdb displayed the write queue below the stream head write queue. Then in the current example, CTRL-U could be entered to pop back to this queue. This is shown below.

^U

struct queue 0x21f7674 S:3

q_qinfo = 0x1f7924 q_pad1[2] = 00
q_first = 0x2156780 q_other = 0x21f7600
q_last = 0x2185800
q_next = 0x0
q_link = 0x0
q_ptr = 0x0029cc48
q_count = 22518
q_flag = 0x1120
QUSE
QOLD
QSYNCH
q_minpsz = 0
q_maxpsz = -1
q_hiwat = 0x8000
q_lowat = 0x4000
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00

When you enter the CTRL-U command, strdb prints the data it saved in the marked entry. If you are running strdb on a running system instead of a core file, the data may not be current. In the above example, the queue may contain different data when CTRL-U is entered than it did when the contents of the queue were pushed on the stack. To see the current values, enter the CTRL-R command. CTRL-R updates the displayed data structure with new values from /dev/kmem. This is shown below. Notice that there are no longer any messages in the queue.

^R

struct queue 0x21f7674 S:3

q_qinfo = 0x1f7924 q_pad1[2] = 00
q_first = 0x0 q_other = 0x21f7600
q_last = 0x0
q_next = 0x0
q_link = 0x0
q_ptr = 0x0029cc48
q_count = 0
q_flag = 0x1120
QUSE
QOLD
QSYNCH
q_minpsz = 0
q_maxpsz = -1
q_hiwat = 0x8000
q_lowat = 0x4000
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00

You may want to use CTRL-R when you are entering navigation commands, not just when you pop the data structure stack. This is because strdb does not automatically update the display when the contents of data structures change. You need to enter the CTRL-R command to update the display with new values from /dev/kmem.

In the previous example, suppose you want to print a field in the queue that strdb does not format. This can be done using :b. The :b command prints the contents of memory starting at a specified address. Optionally, you can specify the number of bytes that :b should print. If you want to see the q_ptr structure, enter the following.

:b 0x29cc48

0x0029cc48 : 00000001 005d9a00 00000000 00000000 |
.....]..........
0x0029cc58 : 00000001 005d8b00 00000000 00000000 | .....]..........
0x0029cc68 : 00000001 00605100 00000000 00000000 | .....`Q.........
0x0029cc78 : 00000000 00000000 00000000 00000000 | ................
0x0029cc88 : 00000000 00000000 00000000 00000000 | ................
0x0029cc98 : 00000000 00000000 00000000 00000000 | ................
0x0029cca8 : 00000000 00000000 00000000 00000000 | ................
0x0029ccb8 : 00000000 00000000 00000000 00000000 | ................
0x0029ccc8 : 00000000 00000000 00000000 00000000 | ................
0x0029ccd8 : 00000000 00000000 00000000 00000000 | ................
0x0029cce8 : 00000000 00000000 00000000 00000000 | ................
0x0029ccf8 : 00000000 00000000 00000000 00000000 | ................
0x0029cd08 : 00000000 00000000 00000000 00000000 | ................
0x0029cd18 : 00000000 00000000 00000000 00000000 | ................
0x0029cd28 : 00000000 00000000 00000000 00000000 | ................
0x0029cd38 : 00000000 00000000 00000000 00000000 | ................

-- Hit any key to continue --

The :x command is often used with :b. If the q_ptr buffer contains a pointer to a STREAMS/UX data structure, you can format the structure using :x. You know that word 0x0029cc4c in the q_ptr buffer contains a queue address, 0x005d9a00. The :x command takes two arguments, a structure address and its type. You can enter :x ? to see which types are accepted by the :x command. This is shown below.

:x ?

known data structure descriptions...
streamtab
msgb
a__datab
datab
free_rtn
queue
qband
qinit
module_info
module_stat
strapush
ioc_pad
iocblk
copyreq
copyresp
stroptions

-- Hit any key to continue --

The type for a STREAMS/UX queue is queue. You can double check which type to use by looking in the include file <sys/stream.h>. An example of entering the :x command to format the queue is shown below.

:x queue 0x5d9a00

struct queue 0x5d9a00 S:4

q_qinfo = 0x294418 q_pad1[1] = 00
q_first = 0x0 q_pad1[2] = 00
q_last = 0x0 q_other = 0x5d9a74
q_next = 0x5ceb00
q_link = 0x0
q_ptr = 0x29cc48
q_count = 0
q_flag = 0x1129
QREADR
QWANTR
QUSE
QOLD
QSYNCH
q_minpsz = 0
q_maxpsz = 256
q_hiwat = 0x8000
q_lowat = 0x4000
q_bandp = 0x5393c0
q_nband = 1
q_pad1[0] = 00

Commands to Change strdb Session Characteristics

After entering strdb, you can enter the :? command to get information about primary commands. Note that primary mode does not prompt for commands; you just enter the command keys.

:?

key - navigate from current structure
^D | :q - exit
^L - refresh
^K - log screen contents if logging enabled
? - show navigation keys for current structure
:? - show known commands
:x ? - show known structure descriptions
:x 'name' 'addr' - show structure 'name' at address 'addr'
:b 'addr' 'len' - show screenful of binary data at address
'addr'
('len' defaults to 256 if not specified)
^P - pop stack
^U - pop stack to previous mark
^T - transpose top stack entries
^R - re-read current structure from memory
:s - enable structure Stacking
:l 'name' 'o|c' - start[o] / stop[c] logging to 'name'
:m - mark current stack location
:u - Unenable structure stacking
:S - STREAMS subsystem commands

There are two types of primary commands, data structure navigation and commands to change strdb session characteristics. This section describes the commands that change strdb session characteristics:

  • :?

  • CTRL-D

  • :q

  • CTRL-L

  • :l

  • :u

  • :s

  • :S

Enter the :? command to see the help menu for primary mode. strdb prints the text shown below.

:?

key - navigate from current structure
^D | :q - exit
^L - refresh
^K - log screen contents if logging enabled
? - show navigation keys for current structure
:? - show known commands
:x ? - show known structure descriptions
:x 'name' 'addr' - show structure 'name' at address 'addr'
:b 'addr' 'len' - show screenful of binary data at address
'addr'
('len' defaults to 256 if not specified)
^P - pop stack
^U - pop stack to previous mark
^T - transpose top stack entries
^R - re-read current structure from memory
:s - enable structure Stacking
:l 'name' 'o|c' - start[o] / stop[c] logging to 'name'
:m - mark current stack location
:u - Unenable structure stacking
:S - STREAMS subsystem commands

Enter the CTRL-D or the :q command to exit from strdb.

Enter the CTRL-L command to refresh the screen.

Enter the :l command to start and stop logging to a file. strdb will log commands and their output to a file. Enter the :l command specifying a file name and the o option to open the log file and start logging. Then you can enter strdb commands and see the output on the terminal. strdb saves a record of the commands and output in the logging file. Once logging is enabled, use CTRL-K to dump the current screen contents to the log file. This allows the user to selectively log debug data and actions taken. You can close the log file and stop logging by entering the :l command, the file name, and the c option. An example is shown below.

:l strdb.log o

No current structure S:0

:S

STREAMS subsystem help commands..
? - show this help menu
h - show this help menu
la 'name' - list all active STREAMS on device 'name'
ll 'name' 'minor' - list all drivers linked under the STREAMS
driver
'name' and minor number 'minor'
lm 'name' 'minor' - list all modules pushed on STREAMS device
'name' and whose minor number is 'minor'
lp 'name' 'minor' - list all drivers persistently linked under
the STREAMS device 'name' and minor number
'minor'
q - quit the STREAMS subsystem commands
qc 'driver' 'file' - print 'driver' read / write side qcount to
file
qh 'name' 'minor' - display STREAM head queue structure
for device 'name' and minor number
'minor'
s [m | d] - Option d lists all the STREAMS drivers
configured in the system. Option m lists
all the modules configured in the system
v - print version of STREAMS structures
displayed

qh tmx 1

struct queue 0x20a2300 S:1

q_qinfo = 0x1f7a18 q_pad1[2] = 00
q_first = 0x0 q_other = 0x20a2374
q_last = 0x0
q_next = 0x0
q_link = 0x0
q_ptr = 0x206d900
q_count = 0
q_flag = 0x1029
QREADR
QWANTR
QUSE
QSYNCH
q_minpsz = 0
q_maxpsz = -1
q_hiwat = 0x200
q_lowat = 0x100
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00

: ^k (screen data is dumped to strdb.log)

:l strdb.log c
:u and :s

When you enter strdb, data structure stacking is enabled. Each time strdb displays a data structure, it pushes it onto a stack. strdb increments and displays the stack depth. Data structure stacking is useful for going back and reviewing data structures that strdb has already displayed. This is described in the previous section, "Data Structure Navigation Commands." You can disable data structure stacking by entering the :u command. When data structure stacking is disabled, strdb does not display the stack depth. Data structure stacking is re-enabled by entering the :s command. An example is shown below. Note how the stack depth displayed in the upper right hand corner of the screen changes.

qh tmx 0

struct queue 0x21f7b00 S:1

q_qinfo = 0x1f7a18 q_pad1[2] = 00
q_first = 0x0 q_other = 0x21f7b74
q_last = 0x0
q_next = 0x0
q_link = 0x0
q_ptr = 0x21f7a00
q_count = 0
q_flag = 0x1029
QREADR
QWANTR
QUSE
QSYNCH
q_minpsz = 0
q_maxpsz = -1
q_hiwat = 0x200
q_lowat = 0x100
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00

:u

struct queue 0x21f7b00

q_qinfo = 0x1f7a18 q_pad1[2] = 00
q_first = 0x0 q_other = 0x21f7b74
q_last = 0x0
q_next = 0x0
q_link = 0x0
q_ptr = 0x21f7a00
q_count = 0
q_flag = 0x1029
QREADR
QWANTR
QUSE
QSYNCH
q_minpsz = 0
q_maxpsz = -1
q_hiwat = 0x200
q_lowat = 0x100
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00

o

struct queue 0x21f7b74

q_qinfo = 0x1f7a34 q_pad1[2] = 00
q_first = 0x0 q_other = 0x21f7b00
q_last = 0x0
q_next = 0x21f7674
q_link = 0x0
q_ptr = 0x21f7a00
q_count = 0
q_flag = 0x102a
QNOENB
QWANTR
QUSE
QSYNCH
q_minpsz = 0
q_maxpsz = -1
q_hiwat = 0x2800
q_lowat = 0x400
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00

:s

struct queue 0x21f7b74 S:1

q_qinfo = 0x1f7a34 q_pad1[2] = 00
q_first = 0x0 q_other = 0x21f7b00
q_last = 0x0
q_next = 0x21f7674
q_link = 0x0
q_ptr = 0x21f7a00
q_count = 0
q_flag = 0x102a
QNOENB
QWANTR
QUSE
QSYNCH
q_minpsz = 0
q_maxpsz = -1
q_hiwat = 0x2800
q_lowat = 0x400
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00
:S

Enter the :S command to switch from primary mode to STREAMS/UX subsystem mode. After invoking strdb, you are in primary mode. Enter :S to switch to STREAMS/UX subsystem mode. In STREAMS/UX subsystem mode, you can see which STREAMS/UX are configured and active on the system. An example is shown below.

strdb

No current structure S:0

:S

STREAMS subsystem help commands..
? - show this help menu
h - show this help menu
la 'name' - list all active STREAMS on device 'name'
ll 'name' 'minor' - list all drivers linked under the STREAMS
driver 'name' and minor number 'minor'
lm 'name' 'minor' - list all modules pushed on STREAMS device
'name' and whose minor number is 'minor'
lp 'name' 'minor' - list all drivers persistently linked under
the
STREAMS device 'name' and minor number
'minor'
q - quit the STREAMS subsystem commands
qc 'driver' 'file' - print 'driver' read / write side qcount
to file
qh 'name' 'minor' - display STREAM head queue structure
for device 'name' and minor number 'minor'
s [m | d] - Option d lists all the STREAMS drivers
configured in the system. Option m lists
all the modules configured in the system
v - print version of STREAMS structures
displayed

Debugging with strdb

This section shows examples of using strdb to debug STREAMS/UX drivers and modules. The examples show how to use strdb on a running system. The adb debugging section of this chapter shows an example of using strdb in conjunction with adb to analyze an HP-UX core file.

Example 1: Flow Control and Fragmentation

In this example, the user has written a loopback driver which uses the qreply STREAMS/UX utility to send all incoming messages up to the stream head read queue.

Figure 6-1 Stream Created By Opening Loopback (lo) Driver

Stream Created By Opening Loopback (lo) Driver

The user writes a simple test for the driver. The test opens lo, writes data to it, reads the data, and then closes the driver. The program is shown below.

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>

main()
{

char wbuf[1024];
char rbuf[1024];
int fd, i, n, cnt;

printf("Open the loopback driver.\n");
fd = open("/dev/lo0", O_RDWR);
if (fd < 0)
printf("Open returned %d and errno = %d.\n",
n, errno);

/* Fill buffer with data to write */
for (n = 0; n < 1024; n++)
wbuf[n] = (char) n;

printf("Call write with nbytes set to 1024.\n");
n = write(fd, wbuf, 1024);
if (n != 1024)
printf("Write returned %d and errno = %d.\n",
n, errno);

printf("Call read to read in the message sent down
stream.\n");
n = read(fd, rbuf, 1024);
if (n != 1024)
printf("Read returned %d and errno =
%d.\n",n,errno);

printf("Close the loopback driver.\n");
close( fd );
}

When the user runs the program, it prints the following results:

Open the loopback driver.
Call write with nbytes set to 1024.
Call read to read in the message sent down stream.
Read returned 512 and errno = 0.
Close the loopback driver.

The user runs strdb to find out why the test program read only 512 bytes of data instead of 1024. First, the user changes the test program to sleep between the write() and read() calls. When the program sleeps, the user runs strdb to see what happened to the data. This is shown below.

strdb

No current structure S:0

The user types :S to enter STREAMS/UX subsystem mode.

:S

STREAMS subsystem help commands..
? - show this help menu
d - print status of STREAMS daemon
h - show this help menu
la 'name' - list all active STREAMS on device 'name'
ll 'name' 'minor' - list all drivers linked under the STREAMS
driver
'name' and minor number 'minor'
lm 'name' 'minor' - list all modules pushed on STREAMS device
'name' and whose minor number is 'minor'
lp 'name' 'minor' - list all drivers persistently linked under
the STREAMS device 'name' and minor number
'minor'
q - quit the STREAMS subsystem commands
qc 'driver' 'file' - print 'driver' read / write side qcount
to file
qh 'name' 'minor' - display STREAM head queue structure
for device 'name' and minor number
'minor'
s [m | d] - Option d lists all the STREAMS drivers
configured in the system. Option m lists
all the modules configured in the system
v - print version of STREAMS structures
displayed

Then the user enters the la command for lo to see what minor number the driver assigned to the stream.

la  lo

stack empty S:0

lo MAJOR = 75
ACTIVE Minor 0x000000 Stream head RQ = 0x00515500

-- Hit any key to continue --

Next, the user enters qh for lo and minor number 0 to start examining the stream. strdb formats the stream head read queue.

qh lo 0

struct queue 0x515500 S:1

q_qinfo = 0x2954f0 q_pad1[2] = 00
q_first = 0x50da00 q_other = 0x515574
q_last = 0x513780
q_next = 0x0
q_link = 0x0
q_ptr = 0x530600
q_count = 512
q_flag = 0x103d
QREADR
QFULL
QWANTR
QWANTW
QUSE
QSYNCH
q_minpsz = 0
q_maxpsz = -1
q_hiwat = 0x200
q_lowat = 0x100
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00

The user notes that q_count, the number of bytes of data on the queue, is 512. This is the amount of data the test program was able to read. The user realizes that the test program could only read 512 bytes, because that is all that was in the queue. The user continues examining the stream in order to find out what happened to the other 512 bytes of data. The user enters the o navigation key to see the other queue, the stream head write queue.

o

struct queue 0x515574 S:2

q_qinfo = 0x29550c q_pad1[2] = 00
q_first = 0x0 q_other = 0x515500
q_last = 0x0
q_next = 0x4bc974
q_link = 0x0
q_ptr = 0x530600
q_count = 0
q_flag = 0x102a
QNOENB
QWANTR
QUSE
QSYNCH
q_minpsz = 0
q_maxpsz = -1
q_hiwat = 0x2800
q_lowat = 0x400
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00

The user sees that there is no data in this queue. The user enters the n key to see the next queue, lo's write queue.

n

struct queue 0x4bc974 S:3

q_qinfo = 0x2951cc q_pad1[2] = 00
q_first = 0x537800 q_other = 0x4bc900
q_last = 0x50d100
q_next = 0x0
q_link = 0x0
q_ptr = 0x2b1fa8
q_count = 512
q_flag = 0x1124
QFULL
QUSE
QOLD
QSYNCH
q_minpsz = 0
q_maxpsz = 256
q_hiwat = 0x200
q_lowat = 0x100
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00

The user sees that the rest of the data is on this queue. The user wonders why the lo driver did not put this data on the stream head write queue. The user enters the CTRL-P command to go back to the stream head read queue.

^P

struct queue 0x515574 S:2

q_qinfo = 0x29550c q_pad1[2] = 00
q_first = 0x0 q_other = 0x515500
q_last = 0x0
q_next = 0x4bc974
q_link = 0x0
q_ptr = 0x530600
q_count = 0
q_flag = 0x102a
QNOENB
QWANTR
QUSE
QSYNCH
q_minpsz = 0
q_maxpsz = -1
q_hiwat = 0x2800
q_lowat = 0x400
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00

^P

struct queue 0x515500 S:1

q_qinfo = 0x2954f0 q_pad1[2] = 00
q_first = 0x50da00 q_other = 0x515574
q_last = 0x513780
q_next = 0x0
q_link = 0x0
q_ptr = 0x530600
q_count = 512
q_flag = 0x103d
QREADR
QFULL
QWANTR
QWANTW
QUSE
QSYNCH
q_minpsz = 0
q_maxpsz = -1
q_hiwat = 0x200
q_lowat = 0x100
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00

The user notices that the QFULL flag is set. This indicates that the queue is flow controlled. q_hiwat is set to 0x200 (512 decimal). Therefore, lo can write only 512 bytes of data to the stream head before a user program does a read, relieving the flow control condition.

The user realizes that this problem occurs because STREAMS/UX fragmented the 1024 bytes into smaller messages. If STREAMS/UX put all the data in one message, lo would put the entire message on the stream head read queue. lo would be able to do this because the driver tests once for flow control before sending the data upstream. Then, when lo tests for flow control, the stream head read queue is empty. lo cannot send all the data when it is fragmented because lo must check for flow control before sending each fragment. After 512 bytes are in the stream head write queue, the flow control check fails.

The user wonders why STREAMS/UX fragmented the data. The user enters m to look at the fragments.

m

struct msgb 0x50da00 S:2

b_next = 0x513780
b_prev = 0x0
b_cont = 0x0
b_rptr = 0x47a700
b_wptr = 0x47a800
b_datap = 0x50da40
b_band = 0
b_pad1 = 00
b_flag = 0x0
b_pad2 = 0

The user notes that there are 256 bytes in this message (b_wptr - b_rptr = 256). The user looks at the next message by entering the n key.

n

struct msgb 0x513780 S:3

b_next = 0x0
b_prev = 0x50da00
b_cont = 0x0
b_rptr = 0x4efc00
b_wptr = 0x4efd00
b_datap = 0x5137c0
b_band = 0
b_pad1 = 00
b_flag = 0x0
b_pad2 = 0

This message also contains 256 bytes. The user enters navigation commands to view lo's write queue. The user examines the sizes of the messages on this queue. They are also 256 bytes. The user reads documentation describing how STREAMS/UX executes the write() system call. According to the stream(2) man page, STREAMS/UX fragments when the data size is larger than the topmost stream module's maxpsz. lo is the topmost stream module; its maxpsz is 256.

The user can fix this problem in two ways. One way is to change the test program to perform multiple reads to receive all the data. Another way is to change the driver's maxpsz to be 1024.

Example 2: Simple Driver Programming Error

In this example, the user has written a loopback driver, sp, which uses timeout to simulate interrupts. sp's put routine calls timeout for each message it receives. When the timeout expires, HP-UX calls sp's timeout function. This function calls putq() to put the message on sp's read queue.

Figure 6-2 Stream Created By Opening Loopback (sp) Driver

Stream Created By Opening Loopback (sp) Driver

The sp_put() routine puts the incoming message on a queue in sp's private data structure before calling timeout(). sp's timeout function takes the first message off the queue, and calls putq to put the message on sp's read queue. sp's open routine saves a pointer to sp's private data structure in the write and read queues' q_ptr field. sp's private data structure and the sp_put() and sp_timeout() routines are shown below.

struct sp {
unsigned sp_state; /* Set to SPOPEN when driver opened. */
/* Cleared when driver is closed. */
queue_t *sp_rdq; /* Contains sp's read q pointer. */
mblk_t *first_mp; /* Pointer to head of message list. */
/* Messages are saved here until */
/* timeout expires. */
mblk_t *last_mp; /* Pointer to tail of message list. */
};

/* Driver state values. */
#define SPOPEN 01

static sp_put(q, mp)
queue_t *q;
mblk_t *mp;
{
struct sp *private;
unsigned int s;
/*
* Check the message type.
*/
switch (mp->b_datap->db_type) {
case M_DATA:
case M_PROTO:
case M_PCPROTO:
/* Raise the spl level to protect private structure,
* since timeout functions such as sp_timeout can
* interrupt sp_put.
*/
s = splstr();
/* Put the message at the tail of the
* private data structure queue.
*/
private = q->q_ptr;
if (!private->last_mp)
private->first_mp = mp;
else
private->last_mp->b_next = mp;
private->last_mp = mp;
splx(s);
/* Set the timeout */
timeout(sp_timeout,private,1);
break;
default:
printf("Routine sp_put: Illegal message %x received.\n",
mp->b_datap->db_type);
break;
}
}

static sp_timeout(private)
struct sp *private;
{
mblk_t *temp;
unsigned int s;

/* Make sure driver isn't being closed. */
if ((private->sp_state & SPOPEN) && (private->first_mp)) {
/* Take message off head of queue in private data
structure. */
temp = private->first_mp;
private->first_mp = private->first_mp->b_next;
temp->b_next = NULL;
/* Call putq to put message on sp's read queue and send
it upstream. */
putq(private->sp_rdq, temp);
}
}

The user writes a test for the driver. The test opens sp, and goes into a loop calling putmsg() to send data and calling getmsg() to receive the data back. The test prints a message each time it receives 100 messages. The user runs the program, but it does not print any messages. While the program is running, the user runs strdb to see what is happening on the stream. This is shown below.

strdb

No current structure S:0

The user types :S to enter STREAMS/UX subsystem mode.

:S

STREAMS subsystem help commands..
? - show this help menu
d - print status of STREAMS daemon
h - show this help menu
la 'name' - list all active STREAMS on device 'name'
ll 'name' 'minor' - list all drivers linked under the STREAMS
driver 'name' and minor number 'minor'
lm 'name' 'minor' - list all modules pushed on STREAMS device
'name' and whose minor number is 'minor'
lp 'name' 'minor' - list all drivers persistently linked under
the STREAMS device 'name' and minor number
'minor'
q - quit the STREAMS subsystem commands
qc 'driver' 'file' - print 'driver' read / write side qcount to
file
qh 'name' 'minor'- display STREAM head queue structure
for device 'name' and minor number 'minor'
s [m | d] - Option d lists all the STREAMS drivers
configured in the system. Option m lists
all the modules configured in the system
v - print version of STREAMS structures
displayed

Then the user enters the la command for sp to see what minor number the driver assigned to the stream.

la  sp

stack empty S:0

sp MAJOR = 115
ACTIVE Minor 0x000000 Stream head RQ = 0x005c1500

-- Hit any key to continue --

Next, the user enters the qh command for sp and minor number 0 to start examining the stream. strdb formats the stream head read queue.

qh sp 0

struct queue 0x5c1500 S:1

q_qinfo = 0x2964f0 q_pad1[2] = 00
q_first = 0x0 q_other = 0x5c1574
q_last = 0x0
q_next = 0x0
q_link = 0x0
q_ptr = 0x5f0100
q_count = 0
q_flag = 0x1029
QREADR
QWANTR
QUSE
QSYNCH
q_minpsz = 0
q_maxpsz = -1
q_hiwat = 0x200
q_lowat = 0x100
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00

The user sees that there are no messages on the stream head read queue. The user decides to look for messages on other queues in the stream. The user enters the o key to see the other queue in this pair, the stream head write queue.

o

struct queue 0x5c1574 S:2

q_qinfo = 0x29650c q_pad1[2] = 00
q_first = 0x0 q_other = 0x5c1500
q_last = 0x0
q_next = 0x605e74
q_link = 0x0
q_ptr = 0x5f0100
q_count = 0
q_flag = 0x102a
QNOENB
QWANTR
QUSE
QSYNCH
q_minpsz = 0
q_maxpsz = -1
q_hiwat = 0x2800
q_lowat = 0x400
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00

The user looks at the next queue, sp's write queue, by entering the n key.

struct queue 0x605e74                                      S:3

q_qinfo = 0x296434 q_pad1[2] = 00
q_first = 0x0 q_other = 0x605e00
q_last = 0x0
q_next = 0x0
q_link = 0x0
q_ptr = 0x29ec48
q_count = 0
q_flag = 0x1128
QWANTR
QUSE
QOLD
QSYNCH
q_minpsz = 0
q_maxpsz = 256
q_hiwat = 0x8000
q_lowat = 0x4000
q_bandp = 0x53b400
q_nband = 1
q_pad1[0] = 00
q_pad1[1] = 00

Next the user enters the o key to look at the other queue in this pair, sp's read queue.

o

struct queue 0x605e00 S:5

q_qinfo = 0x296418 q_pad1[2] = 00
q_first = 0x0 q_other = 0x605e74
q_last = 0x0
q_next = 0x5c1500
q_link = 0x0
q_ptr = 0x29ec48
q_count = 0
q_flag = 0x1129
QREADR
QWANTR
QUSE
QOLD
QSYNCH
q_minpsz = 0
q_maxpsz = 256
q_hiwat = 0x8000
q_lowat = 0x4000
q_bandp = 0x53b3c0
q_nband = 1
q_pad1[0] = 00
q_pad1[1] = 00

The user sees that there are no messages on the stream. Next, the user examines sp's private data structure. The user enters the :b command, specifying the q_ptr field value, 0x29ec48.

:b 0x29ec48

0x0029ec48 : 00000001 00605e00 00000000 005fb600 | .....`^......uq.
0x0029ec58 : 00000000 00000000 00000000 00000000 | ................
0x0029ec68 : 00000000 00000000 00000000 00000000 | ................
0x0029ec78 : 00000000 00000000 00000000 00000000 | ................
0x0029ec88 : 00000000 00000000 00000000 00000000 | ................
0x0029ec98 : 00000000 00000000 00000000 00000000 | ................
0x0029eca8 : 00000000 00000000 00000000 00000000 | ................
0x0029ecb8 : 00000000 00000000 00000000 00000000 | ................
0x0029ecc8 : 00000000 00000000 00000000 00000000 | ................
0x0029ecd8 : 00000000 00000000 00000000 00000000 | ................
0x0029ece8 : 00000000 00000000 00000000 00000000 | ................
0x0029ecf8 : 00000000 00000000 00000000 00000000 | ................
0x0029ed08 : 00000000 00000000 00000000 00000000 | ................
0x0029ed18 : 00000000 00000000 00000000 00000000 | ................
0x0029ed28 : 00000000 00000000 00000000 00000000 | ................
0x0029ed38 : 00000000 00000000 00000000 00000000 | ................

-- Hit any key to continue --

The user sees that the first word of sp's private data structure is 0x00000001. Looking at the sp structure declaration shown above, this word is sp's state. The driver is SPOPEN. The next word of sp's private structure is 0x00605e00. According to the sp struct declaration, this is sp's read queue address. As shown above, strdb also reports that sp's read queue address is 0x00605e00. The next two words are pointers to messages being saved until timeouts expire. The first word is the head of the message queue. Its value is 0x00000000. The second word is the tail. Its value is 0x005fb600. The user does not understand how the head of the list can be 0 and the tail non-zero. The user decides to ask strdb to format the message on the tail of the queue using the :x command. First, the user enters the :x ? command to see the names of the structures that strdb formats.

:x ?

known data structure descriptions...
streamtab
msgb
a__datab
datab
free_rtn
queue
qband
qinit
module_info
module_stat
strapush
ioc_pad
iocblk
copyreq
copyresp
stroptions

-- Hit any key to continue --

The user sees that strdb formats msgb, a message block. The user can double check that this is the correct structure name by looking in the sys/stream.h include file. Then, the user enters the :x command to see the message block.

:x msgb 0x005fb600

struct msgb 0x5fb600 S:6

b_next = 0x5fb700
b_prev = 0x0
b_cont = 0x5fb680
b_rptr = 0x599400
b_wptr = 0x5996ac
b_datap = 0x5fb640
b_band = 0
b_pad1 = 00
b_flag = 0x0
b_pad2 = 0

The user wonders if this is a valid message block. The fields seem to contain correct values. The user checks the data by entering the m key.

m

struct msgb 0x5fb600 Message data at 0x00599400 S:7
0x00599400 : 00000000 00000000 00000005 00000000 | ................
0x00599410 : 00000294 0000070c 6d6e6f70 71727374 | ........mnopqrst
0x00599420 : 75767778 797a6162 63646566 6768696a | uvwxyzabcdefghij
0x00599430 : 6b6c6d6e 6f707172 73747576 7778797a | klmnopqrstuvwxyz
0x00599440 : 61626364 65666768 696a6b6c 6d6e6f70 | abcdefghijklmnop
0x00599450 : 71727374 75767778 797a6162 63646566 | qrstuvwxyzabcdef
0x00599460 : 6768696a 6b6c6d6e 6f707172 73747576 | ghijklmnopqrstuv
0x00599470 : 7778797a 61626364 65666768 696a6b6c | wxyzabcdefghijkl
0x00599480 : 6d6e6f70 71727374 75767778 797a6162 | mnopqrstuvwxyzab
0x00599490 : 63646566 6768696a 6b6c6d6e 6f707172 | cdefghijklmnopqr
0x005994a0 : 73747576 7778797a 61626364 65666768 | stuvwxyzabcdefgh
0x005994b0 : 696a6b6c 6d6e6f70 71727374 75767778 | ijklmnopqrstuvwx
0x005994c0 : 797a6162 63646566 6768696a 6b6c6d6e | yzabcdefghijklmn
0x005994d0 : 6f707172 73747576 7778797a 61626364 | opqrstuvwxyzabcd
0x005994e0 : 65666768 696a6b6c 6d6e6f70 71727374 | efghijklmnopqrst
Type c for more data
Any other key will quit this display

The user knows that this is the data the test program sends. The user wonders what is in the next message. To see the next message, the user enters a key other than c to stop viewing data. Then, the user pops back to the data's message block.

^P

struct msgb 0x5fb600 S:6

b_next = 0x5fb700
b_prev = 0x0
b_cont = 0x5fb680
b_rptr = 0x599400
b_wptr = 0x5996ac
b_datap = 0x5fb640
b_band = 0
b_pad1 = 00
b_flag = 0x0
b_pad2 = 0

Next the user enters the n key to see the next message block.

n

struct msgb 0x5fb700 S:7

b_next = 0x5fb800
b_prev = 0x0
b_cont = 0x5fb780
b_rptr = 0x599800
b_wptr = 0x599b36
b_datap = 0x5fb740
b_band = 0
b_pad1 = 00
b_flag = 0x0
b_pad2 = 0
m

struct msgb 0x5fb700 Message data at 0x00599800 S:8

0x00599800 : 00000000 00000000 00000006 00000000 | ................
0x00599810 : 0000031e 0000081e 7778797a 61626364 | ........wxyzabcd
0x00599820 : 65666768 696a6b6c 6d6e6f70 71727374 | efghijklmnopqrst
0x00599830 : 75767778 797a6162 63646566 6768696a | uvwxyzabcdefghij
0x00599840 : 6b6c6d6e 6f707172 73747576 7778797a | klmnopqrstuvwxyz
0x00599850 : 61626364 65666768 696a6b6c 6d6e6f70 | abcdefghijklmnop
0x00599860 : 71727374 75767778 797a6162 63646566 | qrstuvwxyzabcdef
0x00599870 : 6768696a 6b6c6d6e 6f707172 73747576 | ghijklmnopqrstuv
0x00599880 : 7778797a 61626364 65666768 696a6b6c | wxyzabcdefghijkl
0x00599890 : 6d6e6f70 71727374 75767778 797a6162 | mnopqrstuvwxyzab
0x005998a0 : 63646566 6768696a 6b6c6d6e 6f707172 | cdefghijklmnopqr
0x005998b0 : 73747576 7778797a 61626364 65666768 | stuvwxyzabcdefgh
0x005998c0 : 696a6b6c 6d6e6f70 71727374 75767778 | ijklmnopqrstuvwx
0x005998d0 : 797a6162 63646566 6768696a 6b6c6d6e | yzabcdefghijklmn
0x005998e0 : 6f707172 73747576 7778797a 61626364 | opqrstuvwxyzabcd
Type c for more data
Any other key will quit this display

Again, the values in this message block appear valid. The user double checks the data by entering the m key.

The user continues to look at the message blocks in the list. The list seems to go on indefinitely. It seems as if private->last_mp is being updated correctly, but that private->first_mp is not. Looking at sp_put, the user sees that first_mp is not updated unless last_mp is 0 when the list is empty. It seems as if private->last_mp was not set to 0 correctly. The user looks at sp_timeout() where messages are removed from the list. Indeed, sp_timeout() updates only first_mp. last_mp is not set to zero when the list is empty.

The user changes sp_timeout() to check if the list is empty, and sets private->last_mp to 0 if it is. The corrected function is shown below.

static sp_timeout(private)
struct sp *private;
{
mblk_t *temp;
unsigned int s;

/* Make sure driver isn't being closed. */
if ((private->sp_state & SPOPEN) && (private->first_mp)) {
/* Take message off head of queue in private data structure. */
temp = private->first_mp;
private->first_mp = private->first_mp->b_next;
/* The following statement fixes the bug. */
if (private->first_mp == NULL) private->last_mp = NULL;
temp->b_next = NULL;
/* Call putq to put message on sp's read queue and send it upstream.
*/
putq(private->sp_rdq, temp);
}
}

Example 3: Simple Application Programming Error

In this example, the user writes a test program for the stream described in Example 1. The test program opens several of these STREAMS/UX and execs two processes, one that loops doing putmsgs() and another that loops doing getmsgs(). The test prints a message to the terminal each time it successfully receives 100 STREAMS/UX messages. Some code fragments are shown below.

Put Process

/* Initialize the stream and poll structures */
for (i=0; i<stream_count; i++) {
upper_fd[i].fd = i + OPEN_FILES;
upper_fd[i].events = POLLOUT;
.
.
.
}

/* Loop polling to see which STREAMS are writable and writing to them */
while (1) {

if (poll(upper_fd, stream_count, -1) <= 0) {
err_handler("Poll returned error %d.\n",errno);
}

for (i=0; i < stream_count; i++) {
if (upper_fd[i].revents) {
do_a_put(&(str_ctl[i]), &(upper_fd[i]));
} /* if */
} /* for */
} /* while */

Get Process

/* Initialize the stream and poll structures */
for (i=0; i<stream_count; i++) {
upper_fd[i].fd = i + OPEN_FILES;
upper_fd[i].revents = POLLIN|POLLRDBAND;
.
.
.
}

/* Loop polling to see which STREAMS are readable and reading from them
*/
while (1) {

if (poll(upper_fd, stream_count, -1) <= 0) {
err_handler("Poll returned error %d.\n",errno);
}

for (i=0; i < stream_count; i++) {
if (upper_fd[i].revents) {
do_a_get(&(str_ctl[i]), &(upper_fd[i]));
} /* if */
} /* for */

} /* while */

The user runs the test, but it does not print any messages. The user runs strdb to find the problem.

strdb
No current structure S:0

The user types :S to enter STREAMS/UX subsystem mode.

:S

STREAMS subsystem help commands..
? - show this help menu
d - print status of STREAMS daemon
h - show this help menu
la 'name' - list all active STREAMS on device 'name'
ll 'name' 'minor' - list all drivers linked under the STREAMS
driver 'name' and minor number 'minor'
lm 'name' 'minor' - list all modules pushed on STREAMS device
'name' and whose minor number is 'minor'
lp 'name' 'minor' - list all drivers persistently linked under
the STREAMS device 'name' and minor number
'minor'
q - quit the STREAMS subsystem commands
qc 'driver' 'file' - print 'driver' read / write side qcount to
file
qh 'name' 'minor' - display STREAM head queue structure
for device 'name' and minor number 'minor'
s [m | d] - Option d lists all the STREAMS drivers
configured in the system. Option m lists
all the modules configured in the system
v - print version of STREAMS structures
displayed

Then the user enters the la command for lo to see what minor number the driver assigned to the stream.

la  lo
stack empty S:0

lo MAJOR = 75
ACTIVE Minor 0x000000 Stream head RQ = 0x005c1500

-- Hit any key to continue --

Next the user enters qh for lo and minor number 0 to start examining the stream. strdb formats the stream head read queue.

qh lo 0

struct queue 0x5c1500 S:1

q_qinfo = 0x2944f0 q_pad1[2] = 00
q_first = 0x5e1480 q_other = 0x5eed74
q_last = 0x5e1480
q_next = 0x0
q_link = 0x0
q_ptr = 0x76bf00
q_count = 769
q_flag = 0x103d
QREADR
QFULL
QWANTR
QWANTW
QUSE
QSYNCH
q_minpsz = 0
q_maxpsz = -1
q_hiwat = 0x200
q_lowat = 0x100
q_bandp = 0x0
q_nband = 0
q_pad1[0] = 00
q_pad1[1] = 00

The user notices that the stream head read queue contains several messages that the test program should be able to read. In fact, the queue is full since q_count is greater than q_hiwat, and the QFULL flag is set.

The user goes back to the code for the get process to see if poll() is being called incorrectly. The user checks the parameters passed to poll(). The user sees that the initialization code set revents instead of events before calling poll(). poll() returns 0 in the revents field because no events were requested. The corrected code fragment is shown below.

Get Process

/* Initialize the stream and poll structures */
for (i=0; i<stream_count; i++) {
upper_fd[i].fd = i + OPEN_FILES;
upper_fd[i].events = POLLIN|POLLRDBAND; /* Changed revents to events
*/
.
.
.
}
© 1995 Hewlett-Packard Development Company, L.P.