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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
|
/*-------------------------------------------------------------------------
*
* ipc_test.c
* Simplistic testbed for shared memory and semaphore code.
*
* This file allows for quick "smoke testing" of a PG semaphore or shared
* memory implementation, with less overhead than compiling up a whole
* installation. To use:
* 1. Run configure, then edit src/include/pg_config.h to select the
* USE_xxx_SEMAPHORES and USE_xxx_SHARED_MEMORY settings you want.
* Also, adjust the pg_sema.c and pg_shmem.c symlinks in
* src/backend/port/ if needed.
* 2. In src/backend/port/, do "gmake ipc_test".
* 3. Run ipc_test and see if it works.
* 4. If it seems to work, try building the whole system and running
* the parallel regression tests for a more complete test.
*
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/port/ipc_test.c,v 1.5 2002/09/04 20:31:24 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <errno.h>
#include <unistd.h>
#include "miscadmin.h"
#include "storage/ipc.h"
#include "storage/pg_sema.h"
#include "storage/pg_shmem.h"
/********* stuff needed to satisfy references in shmem/sema code *********/
volatile bool InterruptPending = false;
volatile bool QueryCancelPending = false;
volatile bool ProcDiePending = false;
volatile bool ImmediateInterruptOK = false;
volatile uint32 InterruptHoldoffCount = 0;
volatile uint32 CritSectionCount = 0;
bool IsUnderPostmaster = false;
int MaxBackends = DEF_MAXBACKENDS;
int NBuffers = DEF_NBUFFERS;
#ifndef assert_enabled
bool assert_enabled = true;
#endif
#define MAX_ON_EXITS 20
static struct ONEXIT
{
void (*function) ();
Datum arg;
} on_proc_exit_list[MAX_ON_EXITS], on_shmem_exit_list[MAX_ON_EXITS];
static int on_proc_exit_index,
on_shmem_exit_index;
void
proc_exit(int code)
{
shmem_exit(code);
while (--on_proc_exit_index >= 0)
(*on_proc_exit_list[on_proc_exit_index].function) (code,
on_proc_exit_list[on_proc_exit_index].arg);
exit(code);
}
void
shmem_exit(int code)
{
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;
}
void
on_shmem_exit(void (*function) (), Datum arg)
{
if (on_shmem_exit_index >= MAX_ON_EXITS)
elog(FATAL, "Out of on_shmem_exit slots");
on_shmem_exit_list[on_shmem_exit_index].function = function;
on_shmem_exit_list[on_shmem_exit_index].arg = arg;
++on_shmem_exit_index;
}
void
on_exit_reset(void)
{
on_shmem_exit_index = 0;
on_proc_exit_index = 0;
}
void
RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2)
{
}
void
ProcessInterrupts(void)
{
}
int
ExceptionalCondition(char *conditionName,
char *errorType,
char *fileName,
int lineNumber)
{
fprintf(stderr, "TRAP: %s(\"%s\", File: \"%s\", Line: %d)\n",
errorType, conditionName,
fileName, lineNumber);
abort();
return 0;
}
void
elog(int lev, const char *fmt,...)
{
if (lev >= ERROR)
{
fprintf(stderr, "elog(%s)\n", fmt);
abort();
}
}
/********* here's the actual test *********/
typedef struct MyStorage
{
PGShmemHeader header;
int flag;
PGSemaphoreData sem;
} MyStorage;
int
main(int argc, char **argv)
{
MyStorage *storage;
int cpid;
printf("Creating shared memory ... ");
fflush(stdout);
storage = (MyStorage *) PGSharedMemoryCreate(8192, false, 5433);
storage->flag = 1234;
printf("OK\n");
printf("Creating semaphores ... ");
fflush(stdout);
PGReserveSemaphores(2, 5433);
PGSemaphoreCreate(&storage->sem);
printf("OK\n");
/* sema initial value is 1, so lock should work */
printf("Testing Lock ... ");
fflush(stdout);
PGSemaphoreLock(&storage->sem, false);
printf("OK\n");
/* now sema value is 0, so trylock should fail */
printf("Testing TryLock ... ");
fflush(stdout);
if (PGSemaphoreTryLock(&storage->sem))
printf("unexpected result!\n");
else
printf("OK\n");
/* unlocking twice and then locking twice should work... */
printf("Testing Multiple Lock ... ");
fflush(stdout);
PGSemaphoreUnlock(&storage->sem);
PGSemaphoreUnlock(&storage->sem);
PGSemaphoreLock(&storage->sem, false);
PGSemaphoreLock(&storage->sem, false);
printf("OK\n");
/* check Reset too */
printf("Testing Reset ... ");
fflush(stdout);
PGSemaphoreUnlock(&storage->sem);
PGSemaphoreReset(&storage->sem);
if (PGSemaphoreTryLock(&storage->sem))
printf("unexpected result!\n");
else
printf("OK\n");
/* Fork a child process and see if it can communicate */
printf("Forking child process ... ");
fflush(stdout);
cpid = fork();
if (cpid == 0)
{
/* In child */
on_exit_reset();
sleep(3);
storage->flag++;
PGSemaphoreUnlock(&storage->sem);
proc_exit(0);
}
if (cpid < 0)
{
/* Fork failed */
printf("failed: %s\n", strerror(errno));
proc_exit(1);
}
printf("forked child pid %d OK\n", cpid);
if (storage->flag != 1234)
printf("Wrong value found in shared memory!\n");
printf("Waiting for child (should wait 3 sec here) ... ");
fflush(stdout);
PGSemaphoreLock(&storage->sem, false);
printf("OK\n");
if (storage->flag != 1235)
printf("Wrong value found in shared memory!\n");
/* Test shutdown */
printf("Running shmem_exit processing ... ");
fflush(stdout);
shmem_exit(0);
printf("OK\n");
printf("Tests complete.\n");
proc_exit(0);
return 0; /* not reached */
}
|