Manfred Spraul wrote:
>
> Mark Swanson wrote:
> >
> > Hello,
> >
> > ipcs (msg) gives incorrect results if used-bytes is above 65536. It
> > stays at 65536 even though messages are being read and removed from the
> > msg queue.
> >
Ok, does the value stay at 65536 or 65535?
It should stay at 65535 if you use a too old version of util-linux.
Please upgrade (see linux/Documentation/Changes)
The proc interface at /proc/sysvipc/msg should report the correct
numbers.
If you want to access values > 65535 from your app you have 2 options:
1) use the new msqid64_ds structure. You must pass IPC_64 to the msgctl
call. This is the only option if you need correct 32-bit uids.
Check the util-linux source, I don't have sample code.
msqid64_ds is only supported by the 2.4 kernel.
2) the old msqid_ds structure also support 32-bit queue length, an
unused field was reused. No support for 32-bit uids.
#define msg_lqbytes __rwait;
I've attached my old sample code.
--
Manfred
/*
* This code is public domain sample code.
* Written by Manfred Spraul, 1999
*
* The application must be started by root or
* setuid(root).
*
* $Header: /pub/cvs/ms/ipcmsg/longqueue.c,v 1.2 1999/10/09 23:27:54 manfreds Exp $
*/
#include <sys/msg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* result codes:
* 0: success
* 1: partial success, queue len now USHORT_MAX
* 100: invalid parameters.
* 101: other error
* 256: fatal error, please delete the queue: queue len now 0.
*/
#define USHORT_MAX 0xFFff
struct queuelen {
int llen;
unsigned short slen;
};
struct msqid_ds g_q;
#define msg_lqbytes __rwait
void failure(char* msg)
{
printf(" unexpected error in %s.\n",msg);
exit(101);
}
int init_ipc(int id)
{
int res;
res = msgget(id,0);
if(res == -1)
failure("findkey()");
id = res;
res = msgctl(id,IPC_STAT,&g_q);
if(res == -1)
failure("init_ipc()");
return id;
}
void get_queuelen(int id,
struct queuelen *out)
{
int res;
struct msqid_ds q;
res = msgctl(id,IPC_STAT,&q);
if(res == -1)
failure("get_queuelen()");
out->llen = q.msg_lqbytes;
out->slen = q.msg_qbytes;
}
int set_queuelen(int id, int len)
{
struct msqid_ds q;
memcpy(&q,&g_q,sizeof(q));
if(len > USHORT_MAX) {
q.msg_qbytes = 0;
q.msg_lqbytes = len;
} else
{
q.msg_qbytes = len;
}
return msgctl(id,IPC_SET,&q);
}
int main(int argc,char** argv)
{
int id;
int len;
struct queuelen prev;
struct queuelen new;
printf("longqueue <id> <len>\n");
if(argc != 3) {
printf("Invalid parameters.\n");
return 100;
}
id = atoi(argv[1]);
len = atoi(argv[2]);
if(len <= 0) {
printf("Invalid parameters.\n");
return 100;
}
id = init_ipc(id);
get_queuelen(id,&prev);
if(set_queuelen(id,len) == -1)
failure("set_queuelen()");
if(len <= USHORT_MAX) {
out_success:
get_queuelen(id,&prev);
printf(" new queuelen: (%d,%d).\n",prev.slen,prev.llen);
return 0;
}
/* the old Linux ipcmsg code doesn't support
* long queues. It interprets this as "queue len 0".
* Check for this, and try USHORT_MAX, then the original
* value.
*/
get_queuelen(id,&new);
if(new.slen != 0)
goto out_success;
if(set_queuelen(id,USHORT_MAX) == -1) {
if(set_queuelen(id,prev.slen) == -1) {
printf(" fatal error. queue len now 0.\n");
return 256;
};
failure("set_queuelen()");
}
get_queuelen(id,&new);
printf(" new queuelen: (%d,%d).\n",prev.slen,prev.llen);
return 1;
}