home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / storage / ipc / execipc.c next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  18.1 KB  |  722 lines

  1. /* ----------------------------------------------------------------
  2.  *   FILE
  3.  *    execipc.c
  4.  *    
  5.  *   DESCRIPTION
  6.  *    executor shared memory / semaphore stuff
  7.  *
  8.  *    This code was swiped from the buffer manager and
  9.  *    somewhat simplified.  The whole shared memory / semaphore mess
  10.  *    should probably be thought out better because as it is,
  11.  *    each module that needs shared memory or semaphores has to have
  12.  *    its own functions to create, attach and initialize them.
  13.  *
  14.  *    In my opinion, several modules should register initialization
  15.  *    routines to be called by a single create/attach mechanism at
  16.  *    the appropriate times. -cim 2/27/90
  17.  *
  18.  *    The create/initialize functions are currently called from
  19.  *    {Attach,Create}SharedMemoryAndSemaphores in storage/ipc/ipci.c
  20.  *    which is called from InitCommunication().
  21.  *
  22.  *   INTERFACE ROUTINES
  23.  *    the following are used by the executor proper:
  24.  *    
  25.  *    ParallelExecutorEnabled()    - has become a macro defined in slaves.h
  26.  *    SetParallelExecutorEnabled()    - assign parallel status
  27.  *    GetNumberSlaveBackends()    - has become a macro defined in slaves.h
  28.  *    SetNumberSlaveBackends()    - assign parallel information
  29.  *
  30.  *    I_xxx()            - initialize the specified semaphore
  31.  *    P_xxx()            - P on the specified semaphore
  32.  *    V_xxx()            - V on the specified semaphore
  33.  *
  34.  *    the rest of the functions are used by the ipci.c code during
  35.  *    initialization.
  36.  *
  37.  *   NOTES
  38.  *    This file exists here and not in the executor directory
  39.  *    because these functions are called by the initialization
  40.  *    code which is compiled into cinterface.a.  The executor
  41.  *    directory contains code which is not compiled into cinterface.a
  42.  *    and so this file is here because it should not be there.
  43.  *    It's that simple.
  44.  *
  45.  *    This is once case where its important to know what code
  46.  *    ends up being compiled where.  If this code is moved, this
  47.  *    problem should be kept in mind...
  48.  *
  49.  *   IDENTIFICATION
  50.  *    $Header: /private/postgres/src/storage/ipc/RCS/execipc.c,v 1.16 1991/11/21 13:18:07 hong Exp $
  51.  * ----------------------------------------------------------------
  52.  */
  53.  
  54. /* ----------------
  55.  *    this group of #includes stolen from ipci.c -- these should
  56.  *    be condensed.
  57.  * ----------------
  58.  */
  59. #include "tmp/c.h"
  60.  
  61. #include "storage/ipc.h"
  62. #include "storage/ipci.h"
  63. #include "storage/sinval.h"
  64.  
  65. #include "tcop/slaves.h"
  66. #include "utils/mcxt.h"
  67. #include "utils/log.h"
  68.  
  69.  RcsId("$Header: /private/postgres/src/storage/ipc/RCS/execipc.c,v 1.16 1991/11/21 13:18:07 hong Exp $");
  70.  
  71. /* ----------------
  72.  *    local defines and stuff
  73.  * ----------------
  74.  */
  75. #define EXEC_SHM_SIZE        1024*1024
  76. #define EXEC_SHM_PERMISSION    0700
  77.  
  78. IpcMemoryId     ExecutorMemoryId = -1;
  79. IpcSemaphoreId     ExecutorSemaphoreId = -1;
  80. IpcSemaphoreId     ExecutorSemaphoreId1 = -1;
  81. uint16         ExecNumSem = 0;
  82.  
  83. char    *ExecutorSharedMemory = NULL;
  84. int    ExecutorSharedMemorySize = 0;
  85. int    ParallelExecutorEnableState = 0;
  86. int     NumberSlaveBackends = 0;
  87. int     *ExecutorSemaphoreLockCount = NULL;
  88.  
  89. int     ExecutorSemaphoreArraySize;
  90. int        ExecutorSMSemaphore;
  91. int        ExecutorAbortSemaphore;
  92. int        ExecutorMasterSemaphore;
  93. int        ExecutorSlaveSemStart;
  94.  
  95. ProcGroupInfo ProcGroupInfoP;  /* have to define it here for postmaster to
  96.                   be happy to link, dumb!  */
  97. SlaveInfo SlaveInfoP;
  98. int MyPid = -1;
  99. SlaveLocalInfoData SlaveLocalInfoD = {1, 0, false, -1, 0, false, NULL, NULL};
  100.  
  101. /* ----------------------------------------------------------------
  102.  *            accessor functions
  103.  *
  104.  *    these are here to provide access to variables kept
  105.  *    hidden to other parts of the system.  In particular
  106.  *
  107.  *        SetParallelExecutorEnabled() and
  108.  *        SetNumberSlaveBackends()
  109.  *
  110.  *    Are used to specify parallel information obtained
  111.  *    from the command line,
  112.  *
  113.  *        ParallelExecutorEnabled()
  114.  *
  115.  *    Is used during initialization to decide whether or
  116.  *    not to allocate shared memory and semaphores and also
  117.  *    at runtime to decide how to plan/execute the query.
  118.  *
  119.  * ----------------------------------------------------------------
  120.  */
  121.  
  122.  
  123. void
  124. SetParallelExecutorEnabled(state)
  125.     bool state;
  126. {    
  127.     ParallelExecutorEnableState = (state == true);
  128. }
  129.  
  130. void
  131. SetNumberSlaveBackends(numslaves)
  132.     int numslaves;
  133. {
  134.     NumberSlaveBackends = numslaves;
  135. }
  136.  
  137. /* ----------------------------------------------------------------
  138.  *               semaphore operations
  139.  *
  140.  *    The IpcSemaphoreXXX routines allow operations on named
  141.  *    arrays of semaphores.  The executor semaphores are all
  142.  *    kept in a single array and thus managable via a single
  143.  *    IPCKey.  That way they are easy to clean up from the outside
  144.  *    world.
  145.  *
  146.  *    Exec_I, Exec_P and Exec_V are the "internal" semaphore
  147.  *    interface routines to the Ipc code.  These routines provide
  148.  *    access to the entire array of executor semaphores.  In
  149.  *    addition, these keep track of the number of locks made by
  150.  *    each backend so that when a backend dies, the semaphore locks
  151.  *    can be released.
  152.  *
  153.  *    I_Start, etc. are routines which access specific-purposed
  154.  *    semaphores in the array.  These I_, P_ and V_ routines
  155.  *    are the only ones expected to call the Exec_I, etc routines.
  156.  *    Hence if the code changed or new semaphores are needed,
  157.  *    then this interface guideline should be kept in mind.
  158.  *
  159.  *    Note: in the following code, we always pass negative
  160.  *          arguments to IpcSemaphore{Lock,Unlock}.  Positive
  161.  *          values do the opposite of what the name of the
  162.  *          routine would suggest.
  163.  * ----------------------------------------------------------------
  164.  */
  165.  
  166. /* --------------------------------
  167.  *    ExecImmediateReleaseSemaphore releases all the semaphore
  168.  *    locks placed by this backend.  This is called by exitpg().
  169.  * --------------------------------
  170.  */
  171.  
  172. void
  173. ExecImmediateReleaseSemaphore()
  174. {
  175.     int i;
  176.     int cnt;
  177.     int semno;
  178.     IpcSemaphoreId semid;
  179.  
  180.     for (i=0; i<ExecutorSemaphoreArraySize; i++) {
  181.     if (i < IPC_NMAXSEM) {
  182.         semno = i;
  183.         semid = ExecutorSemaphoreId;
  184.       }
  185.     else {
  186.         semno = i - IPC_NMAXSEM;
  187.         semid = ExecutorSemaphoreId1;
  188.       }
  189.     cnt = ExecutorSemaphoreLockCount[i];
  190.     if (cnt > 0)
  191.         IpcSemaphoreSilentUnlock(semid, semno, -cnt);
  192.     }
  193. }
  194.  
  195. /* --------------------------------
  196.  *    Exec_I sets the value of the specified executor semaphore
  197.  *    We set the lock count to 1-value because a semaphore value
  198.  *    of 1 indicates no processes hold locks on that semaphore.
  199.  * --------------------------------
  200.  */
  201.  
  202. void
  203. Exec_I(semno, value)
  204.     int semno;
  205.     int value;
  206. {
  207.     int i;
  208.     IpcSemaphoreId semid;
  209.  
  210.     if (semno < IPC_NMAXSEM) {
  211.     i = semno;
  212.     semid = ExecutorSemaphoreId;
  213.       }
  214.     else {
  215.        i = semno - IPC_NMAXSEM;
  216.        semid = ExecutorSemaphoreId1;
  217.       }
  218.     IpcSemaphoreSet(semid, i, value);
  219.     ExecutorSemaphoreLockCount[semno] = 1-value;
  220. }
  221.  
  222. /* --------------------------------
  223.  *    Exec_P requests a P (plaatsen) operation on the specified
  224.  *    executor semaphore.  It places "nlocks" locks at once.
  225.  * --------------------------------
  226.  */
  227.  
  228. void
  229. Exec_P(semno, nlocks)
  230.     int semno;
  231.     int nlocks;
  232. {
  233.     int i;
  234.     IpcSemaphoreId semid;
  235.  
  236.     if (semno < IPC_NMAXSEM) {
  237.     i = semno;
  238.     semid = ExecutorSemaphoreId;
  239.       }
  240.     else {
  241.        i = semno - IPC_NMAXSEM;
  242.        semid = ExecutorSemaphoreId1;
  243.       }
  244.     IpcSemaphoreLock(semid, i, -nlocks);
  245.     ExecutorSemaphoreLockCount[semno] += nlocks;
  246. }
  247.  
  248. /* --------------------------------
  249.  *    Exec_V requests a V (vrijlaten) operation on the specified
  250.  *    executor semaphore.  It removes "nlocks" locks at once.
  251.  * --------------------------------
  252.  */
  253.  
  254. void
  255. Exec_V(semno, nlocks)
  256.     int semno;
  257.     int nlocks;
  258. {
  259.     int i;
  260.     IpcSemaphoreId semid;
  261.  
  262.     if (semno < IPC_NMAXSEM) {
  263.     i = semno;
  264.     semid = ExecutorSemaphoreId;
  265.       }
  266.     else {
  267.        i = semno - IPC_NMAXSEM;
  268.        semid = ExecutorSemaphoreId1;
  269.       }
  270.     IpcSemaphoreUnlock(semid, i, -nlocks);
  271.     ExecutorSemaphoreLockCount[semno] -= nlocks;
  272. }
  273.  
  274. /* --------------------------------
  275.  *    external interface to semaphore operations
  276.  * --------------------------------
  277.  */
  278. /* ----------------
  279.  *    the Start(n) semaphores are used to signal the slave backends
  280.  *    to start processing.
  281.  *
  282.  *    Since I_Start sets the semaphore to 0, a process doing P_Start
  283.  *    will wait until after some other process executes a V_Start.
  284.  *
  285.  *    Note: we use local variables because we can tweak them in
  286.  *          dbx easier...
  287.  * ----------------
  288.  */
  289. void
  290. I_Start(x)
  291.     int x;
  292. {
  293.     int value = 0;
  294.     Exec_I(x + ExecutorSlaveSemStart, value);
  295. }
  296.  
  297. void
  298. P_Start(x)
  299.     int x;
  300. {
  301.     int value = 1;
  302.     Exec_P(x + ExecutorSlaveSemStart, value);
  303. }
  304.  
  305. void
  306. V_Start(x)
  307.     int x;
  308. {
  309.     int value = 1;
  310.     Exec_V(x + ExecutorSlaveSemStart, value);
  311. }
  312.  
  313. /* ----------------
  314.  *    the Finished() semaphore is used for the slaves to signal
  315.  *    the master backend that processing is complete.
  316.  *
  317.  *    Note: P_Finished() places nslaves locks at once so that
  318.  *          after nslaves execute V_Finished(), the P will be granted.
  319.  *
  320.  *    Since I_Finished sets the semaphore to 0, a process doing P_Finished
  321.  *    will wait until after some other process executes a V_Finished.
  322.  * ----------------
  323.  */
  324. void
  325. I_Finished()
  326. {
  327.     int value = 0;
  328.     Exec_I(ExecutorMasterSemaphore, value);
  329. }
  330.  
  331. void
  332. P_Finished()
  333. {
  334.     int value = 1;
  335.     Exec_P(ExecutorMasterSemaphore, value);
  336. }
  337.  
  338. void
  339. V_Finished(groupid, scounter, status)
  340. int groupid;
  341. SharedCounter *scounter;
  342. ProcGroupStatus status;
  343. {
  344.     bool is_lastone;
  345.  
  346.     if (scounter->count <= 0) {
  347.     elog(WARN, "V_Finished counter negative.\n");
  348.       }
  349. #ifdef sequent
  350.     S_LOCK(&(scounter->exlock));
  351. #else
  352.     Assert(0); /* you are not supposed to call this routine if you are not
  353.           running on sequent */
  354. #endif
  355.     scounter->count--;
  356.     is_lastone = (bool)(scounter->count == 0);
  357. #ifdef sequent
  358.     S_UNLOCK(&(scounter->exlock));
  359. #endif
  360.     if (is_lastone) {
  361.     /* ----------------
  362.      *  the last slave wakes up the master
  363.      * ----------------
  364.      */
  365.         int value = 1;
  366.     ProcGroupInfoP[groupid].status = status;;
  367.         Exec_V(ExecutorMasterSemaphore, value);
  368.       }
  369. }
  370.  
  371. void
  372. P_FinishedAbort()
  373. {
  374.     int value = GetNumberSlaveBackends();
  375.     Exec_P(ExecutorMasterSemaphore, value);
  376. }
  377.  
  378. void
  379. V_FinishedAbort()
  380. {
  381.     int value = 1;
  382.     Exec_V(ExecutorMasterSemaphore, value);
  383. }
  384.  
  385. /* --------------------------------
  386.  *    InitMWaitOneLock
  387.  *
  388.  *    initialize a one producer multiple consumer lock
  389.  * ---------------------------------
  390.  */
  391. void
  392. InitMWaitOneLock(m1lock)
  393. M1Lock *m1lock;
  394. {
  395.     m1lock->count = 0;
  396. #ifdef HAS_TEST_AND_SET
  397.     S_INIT_LOCK(&(m1lock->waitlock));
  398.     S_LOCK(&(m1lock->waitlock));
  399. #endif
  400. }
  401.     
  402.  
  403. /* --------------------------------
  404.  *    MWaitOne
  405.  *
  406.  *    consumer waits on the producer
  407.  * ---------------------------------
  408.  */
  409. void
  410. MWaitOne(m1lock)
  411. M1Lock *m1lock;
  412. {
  413. #ifdef HAS_TEST_AND_SET
  414.     S_LOCK(&(m1lock->waitlock));
  415.     m1lock->count--;
  416.     if (m1lock->count > 0)
  417.     S_UNLOCK(&(m1lock->waitlock));
  418. #endif
  419. }
  420.  
  421. /* --------------------------------
  422.  *    OneSignalM
  423.  *
  424.  *    producer wakes up all consumers
  425.  * ---------------------------------
  426.  */
  427. void
  428. OneSignalM(m1lock, m)
  429. M1Lock *m1lock;
  430. int m;
  431. {
  432.     m1lock->count = m;
  433. #ifdef HAS_TEST_AND_SET
  434.     S_UNLOCK(&(m1lock->waitlock));
  435. #endif
  436. }
  437.  
  438.  
  439. /* ----------------
  440.  *    the SharedMemoryMutex semaphore is used to restrict concurrent
  441.  *    updates to the executor shared memory allocator meta-data.
  442.  *
  443.  *    Since I_SharedMemoryMutex sets the semaphore to 1, a process
  444.  *    doing P_SharedMemoryMutex will be immediately granted the semaphore.
  445.  * ----------------
  446.  */
  447. void
  448. I_SharedMemoryMutex()
  449. {
  450. #ifndef sequent
  451.     int value = 1;
  452.     Exec_I(ExecutorSMSemaphore, value);
  453. #endif
  454. }
  455.  
  456. void
  457. P_SharedMemoryMutex()
  458. {
  459. #ifdef sequent
  460.     ExclusiveLock(ExecutorSMSemaphore);
  461. #else
  462.     int value = 1;
  463.     Exec_P(ExecutorSMSemaphore, value);
  464. #endif
  465. }
  466.  
  467. void
  468. V_SharedMemoryMutex()
  469. {
  470. #ifdef sequent
  471.     ExclusiveUnlock(ExecutorSMSemaphore);
  472. #else
  473.     int value = 1;
  474.     Exec_V(ExecutorSMSemaphore, value);
  475. #endif
  476. }
  477.  
  478. /* ----------------
  479.  *    the Abort semaphore is used to synchronize abort transaction
  480.  *    processing in the master and slave backends.
  481.  *
  482.  *    Since I_Abort sets the semaphore to 0, a process doing P_Abort
  483.  *    will wait until after some other process executes a V_Abort.
  484.  * ----------------
  485.  */
  486. void
  487. I_Abort()
  488. {
  489.     int value = 0;
  490.     Exec_I(ExecutorAbortSemaphore, value);
  491. }
  492.  
  493. void
  494. P_Abort()
  495. {
  496.     int value = 1;
  497.     Exec_P(ExecutorAbortSemaphore, value);
  498. }
  499.  
  500. void
  501. V_Abort()
  502. {
  503.     int value = 1;
  504.     Exec_V(ExecutorAbortSemaphore, value);
  505. }
  506.  
  507. /* --------------------------------
  508.  *    ExecInitExecutorSemaphore
  509.  *
  510.  *    Note: if the semaphore already exists, IpcSemaphoreCreate()
  511.  *          will return the existing semaphore id.
  512.  * --------------------------------
  513.  */
  514. void
  515. ExecInitExecutorSemaphore(key)
  516.     IPCKey key;
  517. {
  518.     MemoryContext oldContext;
  519.     int status;
  520.     
  521.     /* ----------------
  522.      *    make certain we are in the top memory context
  523.      *  or else allocated stuff will go away after the
  524.      *  first transaction.
  525.      * ----------------
  526.      */
  527.     oldContext = MemoryContextSwitchTo(TopMemoryContext);
  528.     
  529.     /* ----------------
  530.      *    calculate size of semaphore array
  531.      * ----------------
  532.      */
  533.     ExecutorSemaphoreArraySize =
  534. #ifndef sequent
  535.     1 +                /* 1 for shared memory meta-data access */
  536. #endif
  537.     1 +                /* 1 for abort synchronization */
  538.     1 +                /* 1 for master backend synchronization */
  539.     NumberSlaveBackends;        /* n for slave backend synchronization */
  540.     
  541.     /* ----------------
  542.      *    calculate semaphore numbers (indexes into semaphore array)
  543.      * ----------------
  544.      */
  545.     ExecutorAbortSemaphore = 0;
  546.     ExecutorMasterSemaphore = ExecutorAbortSemaphore + 1;
  547.     ExecutorSlaveSemStart =   ExecutorMasterSemaphore + 1;
  548. #ifdef sequent
  549.     ExecutorSMSemaphore = CreateLock();
  550. #else
  551.     ExecutorSMSemaphore = ExecutorSlaveSemStart + 1;
  552. #endif
  553.     
  554.     /* ----------------
  555.      *    create the executor semaphore array.  Note, we don't
  556.      *  want register an on_exit procedure here to kill the semaphores
  557.      *  because this code is executed before we fork().  We have to
  558.      *  register our on_exit progedure after we fork() because only
  559.      *  the master backend should register the on_exit procedure.
  560.      * ----------------
  561.      */
  562.     if (ExecutorSemaphoreArraySize <= IPC_NMAXSEM) {
  563.     ExecutorSemaphoreId =
  564.     IpcSemaphoreCreateWithoutOnExit(key,
  565.                     ExecutorSemaphoreArraySize,
  566.                     IPCProtection,
  567.                     0,
  568.                     &status);
  569.     }
  570.     else {
  571.     ExecutorSemaphoreId =
  572.     IpcSemaphoreCreateWithoutOnExit(key,
  573.                     IPC_NMAXSEM,
  574.                     IPCProtection,
  575.                     0,
  576.                     &status);
  577.     ExecutorSemaphoreId1 =
  578.     IpcSemaphoreCreateWithoutOnExit(key,
  579.                     ExecutorSemaphoreArraySize - IPC_NMAXSEM,
  580.                     IPCProtection,
  581.                     0,
  582.                     &status);
  583.     }
  584.        
  585.     
  586.     /* ----------------
  587.      *    create the semaphore lock count array.  This array keeps
  588.      *  track of the number of locks placed by a backend on the
  589.      *  executor semaphores.  This is needed for releasing locks
  590.      *  on the semaphores when a backend dies.
  591.      * ----------------
  592.      */
  593.     ExecutorSemaphoreLockCount = (int *)
  594.     palloc(ExecutorSemaphoreArraySize * sizeof(int));
  595.     
  596.     /* ----------------
  597.      *    register a function to cleanup when we leave.  This function
  598.      *  only releases semaphore locks so it should be called by all
  599.      *  backends when they exit.  In fact, we have to register this
  600.      *  on_exit procedure here, because later we register the semaphore
  601.      *  kill procedure.  If we registered the kill procedure BEFORE
  602.      *  the release procedure, then the unlock code will try to unlock
  603.      *  non-existant semaphores.  But this isn't a big problem because
  604.      *  we're about to die anyway... -cim 3/15/90
  605.      * ----------------
  606.      */
  607.     on_exitpg(ExecImmediateReleaseSemaphore, (caddr_t) 0);
  608.     
  609.     /* ----------------
  610.      *    return to old memory context
  611.      * ----------------
  612.      */
  613.     (void) MemoryContextSwitchTo(oldContext);
  614. }
  615.  
  616. /* ----------------
  617.  *    ExecSemaphoreOnExit
  618.  *
  619.  *    this function registers the proper on_exit procedure
  620.  *    for the executor semaphores.  This is called in the master
  621.  *    backend AFTER the slaves are fork()'ed so the cleanup
  622.  *    procedure will only fire in the master backend.
  623.  * ----------------
  624.  */
  625. void
  626. ExecSemaphoreOnExit(procedure)
  627.     void (*procedure)();
  628. {
  629.     on_exitpg(procedure, ExecutorSemaphoreId);
  630.     if (ExecutorSemaphoreArraySize > IPC_NMAXSEM)
  631.         on_exitpg(procedure, ExecutorSemaphoreId1);
  632. }
  633.  
  634. /* ----------------------------------------------------------------
  635.  *            shared memory ops
  636.  * ----------------------------------------------------------------
  637.  */
  638.  
  639. /* --------------------------------
  640.  *    ExecCreateExecutorSharedMemory
  641.  * --------------------------------
  642.  */
  643.  
  644. void
  645. ExecCreateExecutorSharedMemory(key)
  646.     IPCKey key;
  647. {
  648.     /* ----------------
  649.      *    calculate the size of the shared memory segment we need.
  650.      *  XXX make this a function of NumberSlaveBackends.
  651.      * ----------------
  652.      */
  653.     ExecutorSharedMemorySize = EXEC_SHM_SIZE;
  654.     
  655.     /* ----------------
  656.      *    create the shared memory segment.  As with the creation
  657.      *  of the semaphores, we don't want to register a cleanup procedure
  658.      *  until after we have fork()'ed, and then we should only register
  659.      *  it in the Master backend.
  660.      * ----------------
  661.      */
  662.     ExecutorMemoryId =
  663.     IpcMemoryCreateWithoutOnExit(key,
  664.                      ExecutorSharedMemorySize,
  665.                      EXEC_SHM_PERMISSION);
  666.     
  667.     if (ExecutorMemoryId < 0)
  668.     elog(FATAL, "ExecCreateExecutorSharedMemory: IpcMemoryCreate failed");
  669. }
  670.  
  671. /* --------------------------------
  672.  *    ExecSharedMemoryOnExit
  673.  *
  674.  *    this function registers the proper on_exit procedure
  675.  *    for the executor shared memory.
  676.  * --------------------------------
  677.  */
  678. void
  679. ExecSharedMemoryOnExit(procedure)
  680.     void (*procedure)();
  681. {
  682.     on_exitpg(procedure, ExecutorMemoryId);
  683. }
  684.  
  685. /* --------------------------------
  686.  *    ExecLocateExecutorSharedMemory
  687.  * --------------------------------
  688.  */
  689.  
  690. void
  691. ExecLocateExecutorSharedMemory(key)
  692.     IPCKey key;
  693. {
  694.     /* ----------------
  695.      *    find the shared memory segment
  696.      * ----------------
  697.      */
  698.     ExecutorMemoryId = IpcMemoryIdGet(key, 0);
  699.     
  700.     if (ExecutorMemoryId < 0)
  701.     elog(FATAL, "ExecLocateExecutorSharedMemory: IpcMemoryIdGet failed");
  702. }
  703.  
  704. /* --------------------------------
  705.  *    ExecAttachExecutorSharedMemory
  706.  * --------------------------------
  707.  */
  708.  
  709. void
  710. ExecAttachExecutorSharedMemory()
  711. {
  712.     /* ----------------
  713.      *    attach to the shared segment
  714.      * ----------------
  715.      */
  716.     ExecutorSharedMemory = IpcMemoryAttach(ExecutorMemoryId);
  717.  
  718.     if (ExecutorSharedMemory == IpcMemAttachFailed)
  719.     elog(FATAL, "ExecAttachExecutorSharedMemory: IpcMemoryAttach failed");
  720.     
  721. }
  722.