1010 * Portions Copyright (c) 1994, Regents of the University of California
1111 *
1212 * IDENTIFICATION
13- * $Header: /cvsroot/pgsql/src/backend/port/sysv_shmem.c,v 1.8 2003/05/06 23:34:55 momjian Exp $
13+ * $Header: /cvsroot/pgsql/src/backend/port/sysv_shmem.c,v 1.9 2003/05/08 14:49:03 momjian Exp $
1414 *
1515 *-------------------------------------------------------------------------
1616 */
@@ -39,9 +39,8 @@ typedef int IpcMemoryId;/* shared memory ID returned by shmget(2) */
3939#define IPCProtection (0600)/* access/modify by user only */
4040
4141
42- #ifdef EXEC_BACKEND
4342IpcMemoryKey UsedShmemSegID = 0 ;
44- #endif
43+ void * UsedShmemSegAddr = NULL ;
4544
4645static void * InternalIpcMemoryCreate (IpcMemoryKey memKey ,uint32 size );
4746static void IpcMemoryDetach (int status ,Datum shmaddr );
@@ -282,7 +281,7 @@ PrivateMemoryDelete(int status, Datum memaddr)
282281 *
283282 * Create a shared memory segment of the given size and initialize its
284283 * standard header. Also, register an on_shmem_exit callback to release
285- * the storage.
284+ * the storage. For an exec'ed backend, it just attaches.
286285 *
287286 * Dead Postgres segments are recycled if found, but we do not fail upon
288287 * collision with non-Postgres shmem segments.The idea here is to detect and
@@ -302,11 +301,9 @@ PGSharedMemoryCreate(uint32 size, bool makePrivate, int port)
302301/* Room for a header? */
303302Assert (size > MAXALIGN (sizeof (PGShmemHeader )));
304303
305- #ifdef EXEC_BACKEND
306- if (UsedShmemSegID != 0 )
304+ if (ExecBackend && UsedShmemSegID != 0 )
307305NextShmemSegID = UsedShmemSegID ;
308306else
309- #endif
310307NextShmemSegID = port * 1000 + 1 ;
311308
312309for (;;NextShmemSegID ++ )
@@ -320,40 +317,59 @@ PGSharedMemoryCreate(uint32 size, bool makePrivate, int port)
320317break ;
321318}
322319
323- /* Try to create new segment */
324- memAddress = InternalIpcMemoryCreate (NextShmemSegID ,size );
325- if (memAddress )
326- break ;/* successful create and attach */
320+ /* If attach to fixed address, only try once */
321+ if (ExecBackend && UsedShmemSegAddr != NULL && NextShmemSegID != UsedShmemSegID )
322+ {
323+ fprintf (stderr ,"Unable to attach to memory at fixed address: shmget(key=%d, addr=%p) failed: %s\n" ,
324+ (int )UsedShmemSegID ,UsedShmemSegAddr ,strerror (errno ));
325+ proc_exit (1 );
326+ }
327+
328+ if (!ExecBackend || UsedShmemSegAddr == NULL )
329+ {
330+ /* Try to create new segment */
331+ memAddress = InternalIpcMemoryCreate (NextShmemSegID ,size );
332+ if (memAddress )
333+ break ;/* successful create and attach */
334+ }
327335
328336/* See if it looks to be leftover from a dead Postgres process */
329337shmid = shmget (NextShmemSegID ,sizeof (PGShmemHeader ),0 );
330338if (shmid < 0 )
331339continue ;/* failed: must be some other app's */
332340
333- #if defined(solaris )&& defined(__sparc__ )
334341/* use intimate shared memory on SPARC Solaris */
335- memAddress = shmat (shmid ,0 ,SHM_SHARE_MMU );
342+ memAddress = shmat (shmid ,UsedShmemSegAddr ,
343+ #if defined(solaris )&& defined (__sparc__ )
344+ SHM_SHARE_MMU
336345#else
337- memAddress = shmat ( shmid , 0 , 0 );
346+ 0
338347#endif
348+ );
339349
340350if (memAddress == (void * )-1 )
341351continue ;/* failed: must be some other app's */
352+
342353hdr = (PGShmemHeader * )memAddress ;
343354if (hdr -> magic != PGShmemMagic )
344355{
345356shmdt (memAddress );
346357continue ;/* segment belongs to a non-Postgres app */
347358}
348359
360+ /* Successfully attached to shared memory, which is all we wanted */
361+ if (ExecBackend && UsedShmemSegAddr != NULL )
362+ break ;
363+
364+ /* Check shared memory and possibly remove and recreate */
365+
349366/*
350- * Ifthe creator PID is my own PID or does not belong to any
351- *extant process, it's safe to zap it .
367+ * IfI am not the creator and it belongs to an extant process,
368+ *continue .
352369 */
353370if (hdr -> creatorPID != getpid ())
354371{
355- if (kill (hdr -> creatorPID ,0 )== 0 ||
356- errno != ESRCH )
372+ if (kill (hdr -> creatorPID ,0 )== 0 || errno != ESRCH )
357373{
358374shmdt (memAddress );
359375continue ;/* segment belongs to a live process */
@@ -385,26 +401,31 @@ PGSharedMemoryCreate(uint32 size, bool makePrivate, int port)
385401 */
386402}
387403
388- /*
389- * OK, we created a new segment. Mark it as created by this process.
390- * The order of assignments here is critical so that another Postgres
391- * process can't see the header as valid but belonging to an invalid
392- * PID!
393- */
394404hdr = (PGShmemHeader * )memAddress ;
395- hdr -> creatorPID = getpid ();
396- hdr -> magic = PGShmemMagic ;
397405
398- /*
399- * Initialize space allocation status for segment.
400- */
401- hdr -> totalsize = size ;
402- hdr -> freeoffset = MAXALIGN (sizeof (PGShmemHeader ));
406+ if (!ExecBackend || makePrivate || UsedShmemSegAddr == NULL )
407+ {
408+ /*
409+ * OK, we created a new segment. Mark it as created by this process.
410+ * The order of assignments here is critical so that another Postgres
411+ * process can't see the header as valid but belonging to an invalid
412+ * PID!
413+ */
414+ hdr -> creatorPID = getpid ();
415+ hdr -> magic = PGShmemMagic ;
416+
417+ /*
418+ * Initialize space allocation status for segment.
419+ */
420+ hdr -> totalsize = size ;
421+ hdr -> freeoffset = MAXALIGN (sizeof (PGShmemHeader ));
422+ }
403423
404- #ifdef EXEC_BACKEND
405- if (!makePrivate && UsedShmemSegID == 0 )
424+ if (ExecBackend && !makePrivate && UsedShmemSegAddr == NULL )
425+ {
426+ UsedShmemSegAddr = memAddress ;
406427UsedShmemSegID = NextShmemSegID ;
407- #endif
428+ }
408429
409430return hdr ;
410431}