File: pool_shmem.c

package info (click to toggle)
pgpool2 3.3.4-1~bpo70%2B1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy-backports
  • size: 9,196 kB
  • sloc: ansic: 59,850; sh: 12,893; yacc: 10,787; lex: 4,637; sql: 743; makefile: 481; java: 469; php: 125; ruby: 98; asm: 5
file content (185 lines) | stat: -rw-r--r-- 4,739 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/* -*-pgsql-c-*- */
/*
 * $Header$
 *
 * pgpool: a language independent connection pool server for PostgreSQL
 * written by Tatsuo Ishii
 *
 * Portions Copyright (c) 2003-2013, PgPool Global Development Group
 * Portions Copyright (c) 2003-2004, PostgreSQL Global Development Group
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose and without fee is hereby
 * granted, provided that the above copyright notice appear in all
 * copies and that both that copyright notice and this permission
 * notice appear in supporting documentation, and that the name of the
 * author not be used in advertising or publicity pertaining to
 * distribution of the software without specific, written prior
 * permission. The author makes no representations about the
 * suitability of this software for any purpose.  It is provided "as
 * is" without express or implied warranty.
 *
 */
#include "pool.h"

#include <errno.h>
#include <string.h>
#include <sys/shm.h>

#include "pool_ipc.h"


#ifdef SHM_SHARE_MMU			/* use intimate shared memory on Solaris */
#define PG_SHMAT_FLAGS			SHM_SHARE_MMU
#else
#define PG_SHMAT_FLAGS			0
#endif


#define MAX_ON_EXITS 64

static struct ONEXIT
{
	void		(*function) (int code, Datum arg);
	Datum		arg;
}	on_shmem_exit_list[MAX_ON_EXITS];

static int	on_shmem_exit_index;


static void IpcMemoryDetach(int status, Datum shmaddr);
static void IpcMemoryDelete(int status, Datum shmId);


/*
 * Create a shared memory segment of the given size and initialize.  Also,
 * register an on_shmem_exit callback to release the storage.
 */
void *
pool_shared_memory_create(size_t size)
{
	int			shmid;
	void	   *memAddress;

	/* Try to create new segment */
	shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | IPC_EXCL | IPCProtection);

	if (shmid < 0)
	{
		pool_error("could not create shared memory segment: %s",
				   strerror(errno));
		return NULL;
	}

	/* Register on-exit routine to delete the new segment */
	on_shmem_exit(IpcMemoryDelete, shmid);

	/* OK, should be able to attach to the segment */
	memAddress = shmat(shmid, NULL, PG_SHMAT_FLAGS);

	if (memAddress == (void *) -1)
	{
		pool_error("shmat(id=%d) failed: %s", shmid, strerror(errno));
		return NULL;
	}

	/* Register on-exit routine to detach new segment before deleting */
	on_shmem_exit(IpcMemoryDetach, (Datum) memAddress);

	return memAddress;
}

/*
 * Removes a shared memory segment from process' address spaceq (called as
 * an on_shmem_exit callback, hence funny argument list)
 */
static void
IpcMemoryDetach(int status, Datum shmaddr)
{
	if (shmdt((void *) shmaddr) < 0)
		pool_log("shmdt(%p) failed: %s", (void *) shmaddr, strerror(errno));
}

/*
 * Deletes a shared memory segment (called as an on_shmem_exit callback,
 * hence funny argument list)
 */
static void
IpcMemoryDelete(int status, Datum shmId)
{
  	struct shmid_ds shmStat;

  	/*
  	 * Is a previously-existing shmem segment still existing and in use?
  	 */
  	if (shmctl(shmId, IPC_STAT, &shmStat) < 0
  		&& (errno == EINVAL || errno == EACCES))
  		return;
  	else if (shmStat.shm_nattch != 0)
  		return;

	if (shmctl(shmId, IPC_RMID, NULL) < 0)
		pool_log("shmctl(%lu, %d, 0) failed: %s",
				 shmId, IPC_RMID, strerror(errno));
}

void
pool_shmem_exit(int code)
{
	shmem_exit(code);
	/* Close syslog connection here as this function is always called on exit */
	closelog();
}

/*
 * Run all of the on_shmem_exit routines --- but don't actually exit.  This
 * is used by the postmaster to re-initialize shared memory and semaphores
 * after a backend dies horribly.
 */
void
shmem_exit(int code)
{
	pool_debug("shmem_exit(%d)", code);

	/*
	 * Call all the registered callbacks.
	 *
	 * As with proc_exit(), we remove each callback from the list before
	 * calling it, to avoid infinite loop in case of error.
	 */
	while (--on_shmem_exit_index >= 0)
		(*on_shmem_exit_list[on_shmem_exit_index].function) (code,
								on_shmem_exit_list[on_shmem_exit_index].arg);

	on_shmem_exit_index = 0;
}

/*
 * This function adds a callback function to the list of functions invoked
 * by shmem_exit().
 */
void
on_shmem_exit(void (*function) (int code, Datum arg), Datum arg)
{
	if (on_shmem_exit_index >= MAX_ON_EXITS)
		pool_error("out of on_shmem_exit slots");
	else
	{
		on_shmem_exit_list[on_shmem_exit_index].function = function;
		on_shmem_exit_list[on_shmem_exit_index].arg = arg;

		++on_shmem_exit_index;
	}
}

/*
 * This function clears all on_proc_exit() and on_shmem_exit() registered
 * functions.  This is used just after forking a backend, so that the
 * backend doesn't believe it should call the postmaster's on-exit routines
 * when it exits...
 */
void
on_exit_reset(void)
{
	on_shmem_exit_index = 0;
}