]> git.8kb.co.uk Git - pgpool-ii/pgpool-ii_2.2.5/blob - pool_shmem.c
Attempt to send a proper failure message to frontend when authentication
[pgpool-ii/pgpool-ii_2.2.5] / pool_shmem.c
1 /* -*-pgsql-c-*- */
2 /*
3  * $Header: /cvsroot/pgpool/pgpool-II/pool_shmem.c,v 1.3.2.2 2009/08/22 04:19:49 t-ishii Exp $
4  *
5  * pgpool: a language independent connection pool server for PostgreSQL
6  * written by Tatsuo Ishii
7  *
8  * Portions Copyright (c) 2003-2009, PgPool Global Development Group
9  * Portions Copyright (c) 2003-2004, PostgreSQL Global Development Group
10  *
11  * Permission to use, copy, modify, and distribute this software and
12  * its documentation for any purpose and without fee is hereby
13  * granted, provided that the above copyright notice appear in all
14  * copies and that both that copyright notice and this permission
15  * notice appear in supporting documentation, and that the name of the
16  * author not be used in advertising or publicity pertaining to
17  * distribution of the software without specific, written prior
18  * permission. The author makes no representations about the
19  * suitability of this software for any purpose.  It is provided "as
20  * is" without express or implied warranty.
21  *
22  */
23 #include "pool.h"
24
25 #include <errno.h>
26 #include <string.h>
27 #include <sys/shm.h>
28
29 #include "pool_ipc.h"
30
31
32 #ifdef SHM_SHARE_MMU                    /* use intimate shared memory on Solaris */
33 #define PG_SHMAT_FLAGS                  SHM_SHARE_MMU
34 #else
35 #define PG_SHMAT_FLAGS                  0
36 #endif
37
38
39 #define MAX_ON_EXITS 20
40
41 static struct ONEXIT
42 {
43         void            (*function) (int code, Datum arg);
44         Datum           arg;
45 }       on_shmem_exit_list[MAX_ON_EXITS];
46
47 static int      on_shmem_exit_index;
48
49
50 static void IpcMemoryDetach(int status, Datum shmaddr);
51 static void IpcMemoryDelete(int status, Datum shmId);
52
53
54 /*
55  * Create a shared memory segment of the given size and initialize.  Also,
56  * register an on_shmem_exit callback to release the storage.
57  */
58 void *
59 pool_shared_memory_create(size_t size)
60 {
61         int                     shmid;
62         void       *memAddress;
63
64         /* Try to create new segment */
65         shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | IPC_EXCL | IPCProtection);
66
67         if (shmid < 0)
68         {
69                 pool_error("could not create shared memory segment: %s",
70                                    strerror(errno));
71                 return NULL;
72         }
73
74         /* Register on-exit routine to delete the new segment */
75         on_shmem_exit(IpcMemoryDelete, shmid);
76
77         /* OK, should be able to attach to the segment */
78         memAddress = shmat(shmid, NULL, PG_SHMAT_FLAGS);
79
80         if (memAddress == (void *) -1)
81         {
82                 pool_error("shmat(id=%d) failed: %s", shmid, strerror(errno));
83                 return NULL;
84         }
85
86         /* Register on-exit routine to detach new segment before deleting */
87         on_shmem_exit(IpcMemoryDetach, (Datum) memAddress);
88
89         return memAddress;
90 }
91
92 /*
93  * Removes a shared memory segment from process' address spaceq (called as
94  * an on_shmem_exit callback, hence funny argument list)
95  */
96 static void
97 IpcMemoryDetach(int status, Datum shmaddr)
98 {
99         if (shmdt((void *) shmaddr) < 0)
100                 pool_log("shmdt(%p) failed: %s", (void *) shmaddr, strerror(errno));
101 }
102
103 /*
104  * Deletes a shared memory segment (called as an on_shmem_exit callback,
105  * hence funny argument list)
106  */
107 static void
108 IpcMemoryDelete(int status, Datum shmId)
109 {
110         struct shmid_ds shmStat;
111
112         /*
113          * Is a previously-existing shmem segment still existing and in use?
114          */
115         if (shmctl(shmId, IPC_STAT, &shmStat) < 0
116                 && (errno == EINVAL || errno == EACCES))
117                 return;
118         else if (shmStat.shm_nattch != 0)
119                 return;
120
121         if (shmctl(shmId, IPC_RMID, NULL) < 0)
122                 pool_log("shmctl(%lu, %d, 0) failed: %s",
123                                  shmId, IPC_RMID, strerror(errno));
124 }
125
126 void
127 pool_shmem_exit(int code)
128 {
129         shmem_exit(code);
130 }
131
132 /*
133  * Run all of the on_shmem_exit routines --- but don't actually exit.  This
134  * is used by the postmaster to re-initialize shared memory and semaphores
135  * after a backend dies horribly.
136  */
137 void
138 shmem_exit(int code)
139 {
140         pool_debug("shmem_exit(%d)", code);
141
142         /*
143          * Call all the registered callbacks.
144          *
145          * As with proc_exit(), we remove each callback from the list before
146          * calling it, to avoid infinite loop in case of error.
147          */
148         while (--on_shmem_exit_index >= 0)
149                 (*on_shmem_exit_list[on_shmem_exit_index].function) (code,
150                                                                 on_shmem_exit_list[on_shmem_exit_index].arg);
151
152         on_shmem_exit_index = 0;
153 }
154
155 /*
156  * This function adds a callback function to the list of functions invoked
157  * by shmem_exit().
158  */
159 void
160 on_shmem_exit(void (*function) (int code, Datum arg), Datum arg)
161 {
162         if (on_shmem_exit_index >= MAX_ON_EXITS)
163                 pool_error("out of on_shmem_exit slots");
164
165         on_shmem_exit_list[on_shmem_exit_index].function = function;
166         on_shmem_exit_list[on_shmem_exit_index].arg = arg;
167
168         ++on_shmem_exit_index;
169 }
170
171 /*
172  * This function clears all on_proc_exit() and on_shmem_exit() registered
173  * functions.  This is used just after forking a backend, so that the
174  * backend doesn't believe it should call the postmaster's on-exit routines
175  * when it exits...
176  */
177 void
178 on_exit_reset(void)
179 {
180         on_shmem_exit_index = 0;
181 }