Re: System V msg queue bugs in latest kernels

From: Manfred Spraul (manfred@colorfullife.com)
Date: Sat Feb 17 2001 - 15:07:16 EST


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; }

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Fri Feb 23 2001 - 21:00:16 EST