Operating System - HP-UX
1748252 Members
3841 Online
108760 Solutions
New Discussion юеВ

Re: shmget returns EINVAL

 
SOLVED
Go to solution
Galen Whipple
New Member

shmget returns EINVAL

I've got a client program that repeatedly accesses shared memory using shmget(), shmat() and shmdt()
It works fine until the server recreates the shared memory segment. Then shmget returns an error with errno = EINVAL. If I then restart the program, it will work until the next night when the server recreates the shared memory segment. Since the shared memory key doesn't change and I call shmget every time to get the memory ID, I don't understand why I can't attach to the new shared memory segment.
9 REPLIES 9
Jeff Schussele
Honored Contributor

Re: shmget returns EINVAL

Hi Galen,

Couple of things.

1) If shmdt() is called then the process must do another shmat() before the next shmget().

2) From the shmat() man page:

[EINVAL] shmid is not a valid shared memory identifier,
(possibly because the shared memory segment was
already removed using shmctl(2) with IPC_RMID), or
the calling process is already attached to shmid.

[EINVAL] shmaddr is not zero and the machine does not
permit nonzero values, or shmaddr is not equal to
the current attach location for the shared memory
segment.

So again the most likely cause is the process is detaching from the segment & then trying to access it w/o reattaching.
May need to trace the process with tusc to validate this.

Rgds,
Jeff
PERSEVERANCE -- Remember, whatever does not kill you only makes you stronger!
Jeff Schussele
Honored Contributor

Re: shmget returns EINVAL

After re-reading your post I have to believe that when "the server recreates the shared memory segment" the process is being forcibly detached from the segment which will, of course, require it to reattach - shmat() - before the next shmget() will succeed. And restarting the process cause the shmat().
Why in the world is the segment being recreated in the first place? How is this being done? Sounds to me like you'll just have to restart the process every time the segment is broken down & recreated.

Rgds,
Jeff
PERSEVERANCE -- Remember, whatever does not kill you only makes you stronger!
A. Clay Stephenson
Acclaimed Contributor

Re: shmget returns EINVAL

If I read what you are doing correctly, it should work. I assume you are doing a shmget(), then a shmat(), and then an immediate shmdt() in the client each time you need to access this shm segment. This is a very strange way to handle shared memory and messages would probably be a better fit. If your shmget() on the client is using a non-zero size parameter for an existing shmid then that could set EINVAL. It would help to know the values that your are using for size and shmflg for the shmget() client system call.

Of course, there is an inherent danger to your use of shared memory and that is synchronization. Even your quick shmget,shmat,shmdt calls on the client could fall at the wrong time.

Probably the best way to handle this is not to recreate the shared memory segment each time. The server process should only create the shared memory segment when the shmid does not already exist. If it exists, let it update the existing data. That way, you could let your client processes remain attached and the problem goes away. You would need to add a bit of flag data toi indicate that yes the server is still running and store this in the segment. It would probably be a good idea to add a semaphore for synchronization issues.
If it ain't broke, I can fix that.
Galen Whipple
New Member

Re: shmget returns EINVAL

Thanks Guys for the quick response.

The shared memory segment is created once a day at midnight by the server. (I don't have access to the server code so I don't know how it is being done.) I access the shared memory sement every 10 seconds all day by doing a shmget(), shmat() and shmdt() sequence. Immediately after midnight I start getting the error return from shmget(). I tried sleeping for 10 seconds before calling shmget again (and repeating for an hour) but I always get the EINVAL return from shmget.
So far, my only option has been to kill the client process and restart it after midnight.
A. Clay Stephenson
Acclaimed Contributor

Re: shmget returns EINVAL

I would still like to see the exact arguments you are passing to shmget() on the client. How are you getting the key? Is is hard-coded or are you using ftok()?
If it ain't broke, I can fix that.
Galen Whipple
New Member

Re: shmget returns EINVAL

Clay,

I read the shared memory key out of a database table. Here are the calls to shmget() shmat() and shmdt().

After the three calls I've included the function that calls them and after the function is the error message generated.

Thanks for your help!
Galen
******************************************

adhere_id = shmget(rtaSession()->memory_id,
rtaSession()->record_count * sizeof(ADHERE), SHM_R)

adhrec = (ADHERE *) shmat(adhere_id, 0,0)
shmdt((void *)adhrec);
*****************************************
#define MAXSHMERRS 3
/* Acesses the shared memory region containing the current SWITCH agent info */
int getAgentsState(char *Switch, AGENT aInfo[])
{
ADHERE *adhrec;
int adhere_id;
int i;
int shmErrs = 0;
char *fmtdate(char *);

/*rtaDebug("Entered getAgentsState ...", __FILE__, __LINE__);*/

shmErrs = 0;
while((adhere_id = shmget(rtaSession()->memory_id,
rtaSession()->record_count * sizeof(ADHERE), SHM_R)) == -1)
{
if(++shmErrs > MAXSHMERRS)
{
char buf[1024];
sprintf(buf, "ERROR: Can't access shared memory.\n"
" shared memory key = 0x%08x\n"
" record count = %d\n"
" error count = %d\n"
" errno = %d\n",
rtaSession()->memory_id,
rtaSession()->record_count, shmErrs, errno);

sleep(60);
rtaExit(rtaSession()->socket, buf, NULL,
__FILE__, __LINE__);

}
sleep(shmErrs*2);
}

/* Get the pointer to shared memory */
shmErrs = 0;
while ((int)( adhrec = (ADHERE *) shmat(adhere_id, 0,0)) == -1)
{
if(++shmErrs > MAXSHMERRS)
{
char buf[1024];
sprintf(buf, "ERROR: Can't attach to shared memory.\n"
" shared memory key = %d\n"
" record count = %d\n"
" error count = %d\n"
" errno = %d\n",
rtaSession()->memory_id,
rtaSession()->record_count, shmErrs, errno);
rtaLog(buf, __FILE__, __LINE__);
/* If we just exit, TotalView will immediately send */
/* another login request, so we'll sleep awhile to */
/* keep the logfile from growing too fast */
sleep (60);
rtaExit(rtaSession()->socket, buf, NULL,
__FILE__, __LINE__);
}
sleep(shmErrs*2);
}

for (i=0; i < rtaSession()->record_count; i++)
{
bzero(aInfo[i], sizeof(AGENT));

sprintf(aInfo[i].agentId, "%d", adhrec[i].login_id);
strcpy(aInfo[i].agentState, adhrec[i].dn1_state);
sprintf(aInfo[i].timeStamp, "%s|%s",
adhrec[i].cur_hms, (char *)fmtdate(adhrec[i].cur_date));
}
shmdt((void *)adhrec);
return (i);
}

******************************************
PID: 27303 PPID: 24538 04222004.000127: File: agent.c Line: 160
DN4DCD: 04222004.000127: ERROR: Can't access shared memory.
shared memory key = 0x000003f2
record count = 718
error count = 4
errno = 22
A. Clay Stephenson
Acclaimed Contributor
Solution

Re: shmget returns EINVAL

Aha! Change your size parameter of your shmget call to 0. You are getting a shmid of an already existing shared memory identifier. If the "new" shared memory segment is smaller than size (unless size is zero), EINVAL is the result. Man 2 shmget for details.
If it ain't broke, I can fix that.
Galen Whipple
New Member

Re: shmget returns EINVAL

Thanks Clay,

I'll try it this weekend.

Galen
A. Clay Stephenson
Acclaimed Contributor

Re: shmget returns EINVAL

While you are tinkering, you still need to address the issue of synchronization --- especially when the server process is being shutdown and restarted. I would do a shmctl(IPC_STAT) after your shmget and look at the time fields at least to decide if it's safe to trust this data. There is, at the very least, a period in which the server has done its shmget to create the new shmid but has not yet populated it. Also, if the server continuously update this data, you may grab partially written data. As I mentioned earlier, normally when this sort of stuff is done, semaphores are used to coordinate the activity but since you don't have the source code, you have to adopt a less robust approach. It sounds to me as though the original developer is in need of a little tweaking via a baseball bat.
If it ain't broke, I can fix that.