X-Recipient: archive-cygwin AT delorie DOT com X-Spam-Check-By: sourceware.org Message-ID: Date: Mon, 5 Nov 2007 09:49:23 -0500 From: "Lev Bishop" To: cygwin AT cygwin DOT com Subject: Re: cygwin stable and cvs snapshot - fork() bug In-Reply-To: MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Disposition: inline References: <20071029083512 DOT GA4224 AT calimero DOT vinschen DOT de> <4725D656 DOT 5090303 AT cygwin DOT com> <20071101095835 DOT GG31224 AT calimero DOT vinschen DOT de> <20071105102147 DOT GI31224 AT calimero DOT vinschen DOT de> Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT cygwin DOT com Mail-Followup-To: cygwin AT cygwin DOT com Delivered-To: mailing list cygwin AT cygwin DOT com Content-Transfer-Encoding: 8bit X-MIME-Autoconverted: from quoted-printable to 8bit by delorie.com id lA5EncTe029411 On 11/5/07, Lev Bishop wrote: > On 11/5/07, Corinna Vinschen wrote: > > On Nov 1 10:58, Corinna Vinschen wrote: > > > On Oct 31 14:26, Lev Bishop wrote: > > > > $ cat lev.c && gcc -o lev lev.c -Wall -Wextra && CYGWIN=server ./lev > > > > #include > > > > #include > > > > #include > > > > > > > > int main(void) > > > > { > > > > int shmid; > > > > if ((shmid = shmget(IPC_PRIVATE, 100,IPC_CREAT | 0600 )) < 0 || > > > > !shmat(shmid, NULL, 0) || > > > > shmctl(shmid, IPC_RMID, NULL) < 0) > > > > puts("problems with shm!"); > > > > fork(); > > > > } > > > > lev.c: In function `main': > > > > lev.c:13: warning: control reaches end of non-void function > > > > 3 [main] lev 1924 c:\Documents and > > > > Settings\Lev\Desktop\mpd-0.13.0\lev.exe: *** fatal error - > > > > MapViewOfFileEx (0x3E0000), Win32 error 6. Terminating. > > > > 124 [main] lev 5076 fork: child 1924 - died waiting for dll > > > > loading, errno 11 > > > > > > Thanks for the testcase. I'm surprised that nobody experienced this > > > problem before. Sorta holiday here, so I'll look into it next week. > > > > Ouch, ouch, ouch. shmctl(IPC_RMID) closed the handle to the shared > > memory, but neglected to remove the actual mappings as well as the > > bookkeeping structure. The result is that after a fork the child thinks > > there are still mappings which have to be duplicated into its own > > memory. But the handle has already been closed in the parent, so the > > MapViewOfFile call fails with "invalid handle". > > > > Unfortunately not many applications use shmctl(IPC_RMID) before creating > > a child process since usually the shared memory is meant to be... well, > > shared. That's why this didn't crop up more often, obviously. > > Are you sure that you're interpreting IPC_RMID correctly? My > understanding is that you can still share the memory until you > actually remove the mapping. (Sort of like how you can unlink() a temp > file immediately after you open it, and continue to use it). I assumed > this was the reason for the create-map-remove pattern used by mpd. > > From the linux man page: > IPC_RMID Mark the segment to be destroyed. The segment will only > actually be destroyed after the last process detaches it > (i.e., when the shm_nattch member of the associated strucā > ture shmid_ds is zero). The caller must be the owner or > creator, or be privileged. If a segment has been marked > for destruction, then the (non-standard) SHM_DEST flag of > the shm_perm.mode field in the associated data structure > retrieved by IPC_STAT will be set. It indeed seems this is behaviour not described in SuSv3. But several unices support (some variant of) this behaviour. At least linux, freebsd, hp-ux, solaris 10 mention it in their man pages, and openbsd and netbsd seem to implement it that way even though they don't describe it in the man pages. FreeBSD: IPC_RMID Removes the segment from the system. The removal will not take effect until all processes having attached the segment have exited; however, once the IPC_RMID operation has taken place, no further processes will be allowed to attach the segment. For the operation to succeed, the calling process's effective uid must match shm_perm.uid or shm_perm.cuid, or the process must have superuser privi- leges. HP-UX: IPC_RMID Remove the shared memory identifier specified by shmid from the system and destroy the shared memory segment and data structure associated with it. If the segment is attached to one or more processes, then the segment key is changed to IPC_PRIVATE and the segment is marked removed. The segment disappears when the last attached process detaches it. This cmd can only be executed by a process that has an effective user ID equal to either that of a user with appropriate privileges or to the value of either shm_perm.uid or shm_perm.cuid in the data structure associated with shmid. Solaris 10: IPC_RMID Remove the shared memory identifier specified by shmid from the system. The segment referenced by the identifier will be destroyed when all processes with the segment attached have either detached the segment or exited. If the segment is not attached to any process when IPC_RMID is invoked, it will be destroyed immediately. This command can be executed only by a process that has appropriate privileges or an effective user ID equal to the value of shm_perm.cuid or shm_perm.uid in the data structure associated with shmid. A further linux extension: In addition to all the above, Linux goes even further and still allows you to attach the segment even after marking it for deletion. Linux man page: Linux permits a process to attach (shmat()) a shared memory segment that has already been marked for deletion using shmctl(IPC_RMID). This feature is not available on other Unix implementations; portable appliā cations should avoid relying on it. Vmware and opera seem to depend on this extension-to-an-extension. Freebsd (since version 5.2) has a sysctl kern.ipc.shm_allow_removed which seems to allow you to force the linux behaviour on this issue. Openbsd automatically does it (only) when running linux binaries via compat_linux(8). If you do implement the behaviour of not destroying the segment until shm_nattach==0, you'll want to make sure that the shared memory key can be reused immediately after the old segment has been IPC_RMIDed, even though the old mapping may still be around. The other OS's which implement it seem to do this by having shmctl(IPC_RMID) change the key of the segment to be IPC_PRIVATE. A cygwin discussion of not being able to reuse a shmid after shmctl(IPC_RMID) is here: http://www.cygwin.com/ml/cygwin/2001-11/msg01446.html It looks like the old cygipc tried to implement the linux behaviour. Don't you just love standards.... Lev -- Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple Problem reports: http://cygwin.com/problems.html Documentation: http://cygwin.com/docs.html FAQ: http://cygwin.com/faq/