File: raghu.html

package info (click to toggle)
lg-issue89 1-1
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 1,804 kB
  • ctags: 80
  • sloc: xml: 106; makefile: 34; sh: 34; perl: 1
file content (444 lines) | stat: -rw-r--r-- 20,140 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
<!--startcut  ==============================================-->
<!-- *** BEGIN HTML header *** -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML><HEAD>
<title>Exploring Message Queues, part 1 LG #89</title>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#0000AF"
ALINK="#FF0000">
<!-- *** END HTML header *** -->

<!-- *** BEGIN navbar *** -->
<!-- *** END navbar *** -->

<!--endcut ============================================================-->

<TABLE BORDER><TR><TD WIDTH="200">
<A HREF="http://www.linuxgazette.com/">
<IMG ALT="LINUX GAZETTE" SRC="../gx/2002/lglogo_200x41.png" 
	WIDTH="200" HEIGHT="41" border="0"></A> 
<BR CLEAR="all">
<SMALL>...<I>making Linux just a little more fun!</I></SMALL>
</TD><TD WIDTH="380">


<CENTER>
<BIG><BIG><STRONG><FONT COLOR="maroon">Exploring Message Queues, part 1</FONT></STRONG></BIG></BIG>
<BR>
<STRONG>By <A HREF="../authors/raghu.html">Raghu J Menon</A></STRONG>
</CENTER>

</TD></TR>
</TABLE>
<P>

<!-- END header -->









<p>Message queues are one of the three IPC (Inter Process Communication) 
facilities provided by the UNIX operating system apart from semaphores and 
shared memory. Message queues appeared in an early release of UNIX system V 
release III as a means of passing messages between processes in an asynchronous 
way.</p>
<p>Let us look at what a message queue actually means. In order for two or more 
processes to communicate with each other, one of them places a message in the 
message queue through some message passing module of the operating system. This 
message placed can be read by some other process. However the access to the 
message by the process is preceded by a clause&nbsp; that the queue and the 
process share a common key.</p>

<H2>A short note on the ipcs command</H2>
<p>The ipcs command displays the currently resident ipcs in the 
operating system. Try typing this command at the prompt, you will obtain an 
output similar to this</p>
<p>&nbsp; ------ Shared Memory Segments --------<br>
key shmid owner perms bytes nattch status <br>
<br>
------ Semaphore Arrays --------<br>
key semid owner perms nsems status <br>
<br>
------ Message Queues --------<br>
key msqid owner perms used-bytes messages <br>
<br>
Our interest is in the last one. A short&nbsp; description of each of the fields 
will come in handy as we proceed further,</p>
<ul>
  <li>key-It is the name that we give to the queue when we create it 
using the msgget() function. </li>
  <li>msqid-It is the value returned by the msgget() function call. 
The operating system recognizes the queue by this name. Any manipulations on the 
queue are based on its id. </li>
  <li>owner-It specifies the creator of the queue.</li>
  <li>perms-The octal value indicated in this field are the 
permissions for various users on the queue. You could compare it with permissions 
granted on a file.</li>
  <li>used-bytes-It indicates the number of bytes of the queue 
currently in use.</li>
  <li>messages-This field indicates the number of messages in the 
queue.</li>
</ul>
<p>&nbsp; </p>

<H2>Creating a Message Queue</H2>
<p>All the IPCs are created using some ipcget() function. Message queues are 
created using the msgget() function. It takes&nbsp; 2 parameters, the key which 
signifies the name given to the queue and a flag variable. The flag variable can 
be either IPC_CREAT or IPC_EXCL. The first of these creates a queue if one does 
not already exist else it simply ignores the parameter. The second forces an 
error message to be flashed onto the screen declaring that a queue by that name 
exists and cloning is unethical in this part of the world. What does the 
function return? Well i suppose you guessed it, it returns the message queue id 
(similar to a file descriptor). 
Now go through the code below and try it on your computer: <a href="misc/raghu/mesg1.c.txt">mesg1.c.</a>  The code 
creates a queue by name 10(This is passed as the first parameter). The key_t data type is nothing but int, do not be confused by it. Now how do you 
ascertain that a queue has indeed been created. Try the following command at 
your prompt i.e.&nbsp; ipcs . This command provides you with data pertaining to 
the IPCs that are living in your system at present. Scan the message queue 
section, you see an entry which has a value of 10(in hex) under the key field 
and a value of 0(usually) under the id field. This entry corresponds to the 
queue that we created above. If you have any doubts regarding that try the 
command before running the program, and see for yourself the difference in the 
output generated.</p>
<p>------ Shared Memory Segments --------<br>
key shmid owner perms bytes nattch status <br>
<br>
------ Semaphore Arrays --------<br>
key semid owner perms nsems status <br>
<br>
------ Message Queues --------<br>
key&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
msqid&nbsp;&nbsp;&nbsp;&nbsp; owner&nbsp;&nbsp;&nbsp; perms&nbsp;&nbsp;&nbsp;&nbsp; 
used-bytes messages <br>
0x0000000a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 666&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
0 <br>
<br>
Okay here is an exercise for you, try replacing the flag 
variable with&nbsp; IPC_CREAT | IPC_EXCL, recompile and run the code. The result 
is obvious since a queue by that name already exists we will encounter an error 
message. Another point to be considered is the value returned by the msgget() 
function incase a queue cannot be created, as is the case when a queue by the id 
already exists and we use the IPC_EXCL flag in the call to msgget(). The return&nbsp; 
value in such a case is a negative value. If we want the queue with the id to be 
created we need to remove the one already present with the same id, well just 
type the following at the command prompt ipcrm msg &lt;id-number&gt;.
 </p>

<H2>Queue Permissions</H2>
<p>A queue as created above is more of a church bell that can be rung by anyone. 
What i actually&nbsp; mean is that just as files have permission fields that 
restrict their access and modification by users of the operating system, so do 
queues. To set the permission fields&nbsp; for a message queue uses the flag 
parameter in the msgget() function along with IPC_CREAT and IPC_EXCL. To specify 
the permissions we need to OR IPC_CREAT with the value in octal that signifies 
the permission. Try out the code below: <a href="misc/raghu/mesg.c.txt">mesg.c</a>  There is no difference from the previous 
one except that the second field in the msgget() function has the value 0644 
ORed with it. This queue is created with read-write mode for the owner and read 
only mode for everyone else. Thus we have a queue that is available for every 
user of the system but only granting read permission. A point to be noted in this context is 
that it is meaningless to have execute permission granted as a queue cannot be 
executed only a code can be executed). A read-write permission to all would mean 
to use the value 0666 instead of the one specified above.&nbsp;  </p>

<H2>Where is the queue information stored?</H2>
<p>For every queue that we create, the information is stored in 
the following structure.</p>
<p>The structure has been defined in the file bits/msg.h. For the 
purpose of file inclusion in our programs though we use the file sys/msg.h</p>

<PRE>
/* Structure of record for one message inside the kernel.
The type `struct msg' is opaque. __time_t is of type long int. All the data 
types are defined in types.h header file*/
struct msqid_ds
{
struct ipc_perm msg_perm; /* structure describing operation permission */
__time_t msg_stime; /* time of last msgsnd (see below ) command */
unsigned long int __unused1;
__time_t msg_rtime; /* time of last msgrcv (see below) command */
unsigned long int __unused2;
__time_t msg_ctime; /* time of last change */
unsigned long int __unused3;
unsigned long int __msg_cbytes; /* current number of bytes on queue */
msgqnum_t msg_qnum; /* number of messages currently on queue */
msglen_t msg_qbytes; /* max number of bytes allowed on queue */
__pid_t msg_lspid; /* pid of last msgsnd() */
__pid_t msg_lrpid; /* pid of last msgrcv() */
unsigned long int __unused4;
unsigned long int __unused5;
};
</PRE>

<p>The first element of the structure is another structure which 
has the following declaration in bits/ipc.h,for inclusion purpose we use the 
file sys/ipc.h.

<PRE>
/* Data structure used to pass permission information to IPC operations. */
struct ipc_perm
{
__key_t __key; /* Key. */
__uid_t uid; /* Owner's user ID. */
__gid_t gid; /* Owner's group ID. */
__uid_t cuid; /* Creator's user ID. */
__gid_t cgid; /* Creator's group ID. */
unsigned short int mode; /* Read/write permission. */
unsigned short int __pad1;
unsigned short int __seq; /* Sequence number. */
unsigned short int __pad2;
unsigned long int __unused1;
unsigned long int __unused2;
};
</PRE>
&nbsp;</p>
<p>The ipc_perm is the structure dealing with user,group id's and 
permissions. </p>

<H3>Controlling The Message Queue</H3>
<p>A queue once created can be modified. This implies that the 
creator or an authorized user can change the permissions and characteristics of 
the queue. The function msgctl() is used for carrying out the modifications. The 
function has the following definition.</p>
<p>int msgctl(int msqid, int cmd, struct msqid_ds *queuestat )<br>
<br>
The first parameter msqid&nbsp; is the id of the queue that we intend to modify, 
the value must be one that already exists.</p>
<p>The cmd argument can be any one of the following.</p>
<ul>
  <li>IPC_STAT -- Place information about the status of the queue in 
the data structure pointed to by queuestat. The process must have read 
permission for this call to succeed. This option essentially fills the structure 
that we defined above with the information of the queue with id msqid.&nbsp;&nbsp;
<br>
&nbsp;</li>
  <li>IPC_SET -- Set the owner's user and group ID, the permissions, 
and the size (in number of bytes) of the message queue. A process must have the 
effective user ID of the owner, creator, or superuser for this call to succeed. 
Under this option the user is granted the freedom to modify the fields within 
the structure msqid_ds of the queue with id msqid. But the freedom is limited 
though as the only fields modifiable are msqid_ds.msg_perm.uid, 
msqid_ds.msg_perm.gid, msqid_ds.msg_perm.mode and msg_qbytes. The msqid_ds in 
our case&nbsp; the pointer queuestat , msg_perm has been 
defined as of type struct ipc_perm in the msqid_ds struct which has been 
  explained above.</li>
  <li>&nbsp;IPC_RMID -- Remove the message queue specified by the msqid argument. That needs 
no more explanation.</li>
</ul>
<p><br>
The following c code will illustrate elements within the structure:
<a href="misc/raghu/qinfo.c.txt">qinfo.c</a> The message queue id number is passed 
as a command line argument. This id is that of an already present queue, so 
select one from the output of the ipcs command. The msgctl() function fills in 
the structure pointed to by qstatus which is of type struct msqid_ds. The rest 
of the code just prints various characteristics of the queue. It will be a good 
idea to just compile and run the send.c code given at the end and then running 
the qinfo code.</p>
<p>With all the knowledge that we have gained so far it is time 
we started communicating with the queues, which is what they are used for.</p>

<H3>Sending and Receiving Messages</H3>
<p>In order to send and receive messages the UNIX based operating 
systems provide two functions msgsnd() to send messages and msgrcv() to receive 
messages. The definition of both the functions are as defined below.</p>
<pre>int msgsnd (int msqid, const void *msgp, size_t msgsz,
          int msgflg);

int msgrcv (int msqid, void *msgp, size_t msgsz, long msgtyp,
          int msgflg);</pre>

<P>
Let us first look at the msgsnd() function, it takes 
  4 parameters, the first one is the queue id of an existing queue. The 2 
  argument is the msgp or message pointer that contains the address of the of a 
  structure that holds the message and its type. This structure is described 
  below.

<PRE>
struct message{
    long mtype; //The message type.
    char mesg [MSGSZ];//The message is of length MSGSZ.
};
</PRE>

<p>The 3 parameter MSGSZ is the length of the message sent in 
bytes. The final parameter msgflg specifies the action to be taken if one or 
more of the following are true.</p>
  <ul>
    <li>The number of bytes already in the queue is equal to 
    msg_qbytes. This value is stored in the queue structure msqid_ds.</li>
    <li>The total number of messages on all queues on the system 
    has reached a maximum limit that is imposed by the system.</li>
  </ul>
<p>What are the actions to be taken in each of these cases?</p>
  <ul>
    <li>If (<tt>msgflg 
    &amp; IPC_NOWAIT</tt>) is 
    non-zero, the message will not be sent and the calling process will return 
    immediately. </li>
    <li>If (<tt>msgflg 
    &amp; IPC_NOWAIT</tt>) is 0, 
    the calling process will suspend execution until one of the following 
    occurs: 
    <ul>
      <li>The condition responsible for 
      the suspension no longer exists, in which case the message is sent. 
      </li>
      <li>The message queue identifier
      <tt>msqid</tt> 
      is removed from the system; when this occurs, <tt>
      errno</tt> 
      is set equal to <tt>EIDRM</tt> 
      and -1 is returned. </li>
      <li>The calling process receives a 
      signal that is to be caught; in this case the message is not sent and the 
      calling process resumes execution. </li>
    </ul>
    <p>Upon successful completion, the 
    following actions are taken with respect to the data structure associated 
    with <tt>msqid</tt>:
    
    <ul>
      <li><tt>msg_qnum</tt> 
      is incremented by 1 i.e. the count of number of messages in the queue&nbsp; 
      is incremented by 1.</li>
      <li><tt>msg_lspid</tt> 
      is set equal to the process ID of the calling process. The msg_lspid field 
      contains the pid of the process that last accessed the queue. </li>
      <li><tt>msg_stime</tt> 
      is set equal to the current time. The msg_stime field holds the time the 
      last message was sent to the queue.</li>
    </ul>
    </li>
  </ul>
<p>The above fields are elements of&nbsp; 
the msqid_ds structure. The msgrcv() function has an additional parameter in 
msgtype which is the received message's type as specified by the sending 
process. Only messages with matching priorities will be printed on the screen. 
Further explanation is provided in recv.c. </p>
<p>The ensuing programs will give you a perfect idea of what we 
have been talking till now. The code below presents the idea of message passing 
between 2 processes. send.c is the code that creates a message queue and puts a 
message into it. recv.c reads that message from the queue.</p>
<p><a href="misc/raghu/send.c.txt">send.c</a></p>
<p><a href="misc/raghu/recv.c.txt">recv.c</a></p>
<p>How does send.c work?</p>
<p>The code begins by defining a structure msgbuf that will hold 
the message to be put in the queue. It contains 2 fields as explained earlier, 
the type field mtype and the message that is stored in an array mtext. A queue 
is then created using the msget function with a key value 10 and the flag 
parameter being IPC_CREAT|0666 whereby we give read permission to all users. We 
give a priority of 1 to the message by setting the mtype field as 1. We then 
copy the text &quot;I am in the queue&quot; into the array mtext which is our message 
array. We are ready to send the message to the queue that we just created 
by invoking the msgsnd() function with the IPC_NOWAIT option (check above for 
the explanation of the function). At each stage of a function call we check for 
errors using the perror() function.</p>
<p>&nbsp;Now recv.c.</p>
<p>This is a straightforward code. This code too begins by 
defining a structure that will hold the message obtained from the queue. The 
code proceeds by creating a queue with the key value 10, if it already exists 
then the queue-id is obtained. A point to be noted here is that only those 
processes having the same key value as the one we had created in send.c can 
access the queue. You can draw analogy to&nbsp; two people holding the key for 
the same lock. If one them locks it only he or the other person can open it, no 
one else can (you can of course break it open!). The msgrcv() function then 
acquires the message from the queue into rbuf which is then subsequently printed 
out. The fourth argument in msgrcv() is 1, could you figure out why? As 
explained earlier the program send.c had sent the message with priority 1, in 
order for the message in queue to be displayed on screen when recv.c is run it 
should have matching priority, this explains the reason why 1 is passed as the 
fourth parameter. The fifth parameter msgflag is 0 just ignore it (i say that 
because that is what is done) or you could do it the right way by specifying it 
to be IPC_NOWAIT|MSG_NOERROR , with this flag the receiver ignores the error 
that might be caused due to the inconsistency in the&nbsp; length of the message 
received and the length parameter passed. If the received message is of greater length 
than MSGSZ an error is reported if MSG_NOERROR is not used. Try the ipcs command 
after running&nbsp; send.c and later on running recv.c. The outputs will 
be similar to ones shown below.</p>
<p>After send.c:</p>

<PRE>
------ Shared Memory Segments -------- 
key shmid owner perms bytes nattch status 
------ Semaphore Arrays --------
key semid owner perms nsems status 
------ Message Queues -------- 
key             msqid       owner perms used-bytes messages 
0x0000000a      65536       root  666   19         1 
</PRE>

After recv.c:
<PRE>
------ Shared Memory Segments -------- 
key shmid owner perms bytes nattch status 
------ Semaphore Arrays -------- 
key semid owner perms nsems status 
------Message Queues --------
key           msqid        owner   perms used-bytes messages
0x0000000a    65536        root      666        0            0 
</PRE>
<p>Notice the difference in the fields used-bytes and messages. 
The message filled into the queue 10 by send.c was consumed by recv.c.</p>
<p>A good variation that you might try out is to check the effect 
of negative priority values. Modify send.c by entering into the queue more than 
one message (say 3) with priorities set to 1,2 and 3. Also modify recv.c by 
setting the priority field to -2 and later -3. What happened? By letting the 
priority field to be a negative value say -n the recv.c displays all the 
messages starting from priority 1,2,3.....n. Why do we need it? Well if you set n to be a 
very large number say 1000,we could get the queue emptied. </p>
<p>In future issues we will explore more complex 
applications of message queues.</p>












<!-- *** BEGIN author bio *** -->
<P>&nbsp;
<P>
<!-- *** BEGIN bio *** -->
<P>
<img ALIGN="LEFT" ALT="[BIO]" SRC="../gx/2002/note.png">
<em>
I am a final year student doing my Btech in Computer Science 
and Engineering at Government Engineering College Trichur, Kerala, India. For me 
knowledge is a ceaseless quest for truth.
</em>
<br CLEAR="all">
<!-- *** END bio *** -->

<!-- *** END author bio *** -->


<!-- *** BEGIN copyright *** -->
<hr>
<CENTER><SMALL><STRONG>
Copyright &copy; 2003, Raghu J Menon.
Copying license <A HREF="../copying.html">http://www.linuxgazette.com/copying.html</A><BR> 
Published in Issue 89 of <i>Linux Gazette</i>, April 2003
</STRONG></SMALL></CENTER>
<!-- *** END copyright *** -->
<HR>

<!--startcut ==========================================================-->
<CENTER>
<!-- *** BEGIN navbar *** -->
<!-- *** END navbar *** -->
</CENTER>
</BODY></HTML>
<!--endcut ============================================================-->