00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "postgres.h"
00014
00015 #include "miscadmin.h"
00016 #include "storage/ipc.h"
00017 #include "storage/pg_shmem.h"
00018
00019 HANDLE UsedShmemSegID = 0;
00020 void *UsedShmemSegAddr = NULL;
00021 static Size UsedShmemSegSize = 0;
00022
00023 static void pgwin32_SharedMemoryDelete(int status, Datum shmId);
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 static char *
00039 GetSharedMemName(void)
00040 {
00041 char *retptr;
00042 DWORD bufsize;
00043 DWORD r;
00044 char *cp;
00045
00046 bufsize = GetFullPathName(DataDir, 0, NULL, NULL);
00047 if (bufsize == 0)
00048 elog(FATAL, "could not get size for full pathname of datadir %s: error code %lu",
00049 DataDir, GetLastError());
00050
00051 retptr = malloc(bufsize + 18);
00052 if (retptr == NULL)
00053 elog(FATAL, "could not allocate memory for shared memory name");
00054
00055 strcpy(retptr, "Global\\PostgreSQL:");
00056 r = GetFullPathName(DataDir, bufsize, retptr + 18, NULL);
00057 if (r == 0 || r > bufsize)
00058 elog(FATAL, "could not generate full pathname for datadir %s: error code %lu",
00059 DataDir, GetLastError());
00060
00061
00062
00063
00064
00065
00066
00067 for (cp = retptr; *cp; cp++)
00068 if (*cp == '\\')
00069 *cp = '/';
00070
00071 return retptr;
00072 }
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087 bool
00088 PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2)
00089 {
00090 char *szShareMem;
00091 HANDLE hmap;
00092
00093 szShareMem = GetSharedMemName();
00094
00095 hmap = OpenFileMapping(FILE_MAP_READ, FALSE, szShareMem);
00096
00097 free(szShareMem);
00098
00099 if (hmap == NULL)
00100 return false;
00101
00102 CloseHandle(hmap);
00103 return true;
00104 }
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119 PGShmemHeader *
00120 PGSharedMemoryCreate(Size size, bool makePrivate, int port)
00121 {
00122 void *memAddress;
00123 PGShmemHeader *hdr;
00124 HANDLE hmap,
00125 hmap2;
00126 char *szShareMem;
00127 int i;
00128 DWORD size_high;
00129 DWORD size_low;
00130
00131
00132 Assert(size > MAXALIGN(sizeof(PGShmemHeader)));
00133
00134 szShareMem = GetSharedMemName();
00135
00136 UsedShmemSegAddr = NULL;
00137
00138 #ifdef _WIN64
00139 size_high = size >> 32;
00140 #else
00141 size_high = 0;
00142 #endif
00143 size_low = (DWORD) size;
00144
00145
00146
00147
00148
00149
00150
00151 for (i = 0; i < 10; i++)
00152 {
00153
00154
00155
00156
00157 SetLastError(0);
00158
00159 hmap = CreateFileMapping(INVALID_HANDLE_VALUE,
00160 NULL,
00161 PAGE_READWRITE,
00162 size_high,
00163 size_low,
00164 szShareMem);
00165
00166 if (!hmap)
00167 ereport(FATAL,
00168 (errmsg("could not create shared memory segment: error code %lu", GetLastError()),
00169 errdetail("Failed system call was CreateFileMapping(size=%lu, name=%s).",
00170 (unsigned long) size, szShareMem)));
00171
00172
00173
00174
00175
00176 if (GetLastError() == ERROR_ALREADY_EXISTS)
00177 {
00178 CloseHandle(hmap);
00179
00180 hmap = NULL;
00181 Sleep(1000);
00182 continue;
00183 }
00184 break;
00185 }
00186
00187
00188
00189
00190
00191 if (!hmap)
00192 ereport(FATAL,
00193 (errmsg("pre-existing shared memory block is still in use"),
00194 errhint("Check if there are any old server processes still running, and terminate them.")));
00195
00196 free(szShareMem);
00197
00198
00199
00200
00201 if (!DuplicateHandle(GetCurrentProcess(), hmap, GetCurrentProcess(), &hmap2, 0, TRUE, DUPLICATE_SAME_ACCESS))
00202 ereport(FATAL,
00203 (errmsg("could not create shared memory segment: error code %lu", GetLastError()),
00204 errdetail("Failed system call was DuplicateHandle.")));
00205
00206
00207
00208
00209
00210 if (!CloseHandle(hmap))
00211 elog(LOG, "could not close handle to shared memory: error code %lu", GetLastError());
00212
00213
00214
00215 on_shmem_exit(pgwin32_SharedMemoryDelete, PointerGetDatum(hmap2));
00216
00217
00218
00219
00220
00221 memAddress = MapViewOfFileEx(hmap2, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0, NULL);
00222 if (!memAddress)
00223 ereport(FATAL,
00224 (errmsg("could not create shared memory segment: error code %lu", GetLastError()),
00225 errdetail("Failed system call was MapViewOfFileEx.")));
00226
00227
00228
00229
00230
00231
00232
00233
00234 hdr = (PGShmemHeader *) memAddress;
00235 hdr->creatorPID = getpid();
00236 hdr->magic = PGShmemMagic;
00237
00238
00239
00240
00241 hdr->totalsize = size;
00242 hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader));
00243
00244
00245 UsedShmemSegAddr = memAddress;
00246 UsedShmemSegSize = size;
00247 UsedShmemSegID = hmap2;
00248
00249 return hdr;
00250 }
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262 void
00263 PGSharedMemoryReAttach(void)
00264 {
00265 PGShmemHeader *hdr;
00266 void *origUsedShmemSegAddr = UsedShmemSegAddr;
00267
00268 Assert(UsedShmemSegAddr != NULL);
00269 Assert(IsUnderPostmaster);
00270
00271
00272
00273
00274 if (VirtualFree(UsedShmemSegAddr, 0, MEM_RELEASE) == 0)
00275 elog(FATAL, "failed to release reserved memory region (addr=%p): error code %lu",
00276 UsedShmemSegAddr, GetLastError());
00277
00278 hdr = (PGShmemHeader *) MapViewOfFileEx(UsedShmemSegID, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0, UsedShmemSegAddr);
00279 if (!hdr)
00280 elog(FATAL, "could not reattach to shared memory (key=%p, addr=%p): error code %lu",
00281 UsedShmemSegID, UsedShmemSegAddr, GetLastError());
00282 if (hdr != origUsedShmemSegAddr)
00283 elog(FATAL, "reattaching to shared memory returned unexpected address (got %p, expected %p)",
00284 hdr, origUsedShmemSegAddr);
00285 if (hdr->magic != PGShmemMagic)
00286 elog(FATAL, "reattaching to shared memory returned non-PostgreSQL memory");
00287
00288 UsedShmemSegAddr = hdr;
00289 }
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299 void
00300 PGSharedMemoryDetach(void)
00301 {
00302 if (UsedShmemSegAddr != NULL)
00303 {
00304 if (!UnmapViewOfFile(UsedShmemSegAddr))
00305 elog(LOG, "could not unmap view of shared memory: error code %lu", GetLastError());
00306
00307 UsedShmemSegAddr = NULL;
00308 }
00309 }
00310
00311
00312
00313
00314
00315
00316 static void
00317 pgwin32_SharedMemoryDelete(int status, Datum shmId)
00318 {
00319 PGSharedMemoryDetach();
00320 if (!CloseHandle(DatumGetPointer(shmId)))
00321 elog(LOG, "could not close handle to shared memory: error code %lu", GetLastError());
00322 }
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341 int
00342 pgwin32_ReserveSharedMemoryRegion(HANDLE hChild)
00343 {
00344 void *address;
00345
00346 Assert(UsedShmemSegAddr != NULL);
00347 Assert(UsedShmemSegSize != 0);
00348
00349 address = VirtualAllocEx(hChild, UsedShmemSegAddr, UsedShmemSegSize,
00350 MEM_RESERVE, PAGE_READWRITE);
00351 if (address == NULL)
00352 {
00353
00354 elog(LOG, "could not reserve shared memory region (addr=%p) for child %p: error code %lu",
00355 UsedShmemSegAddr, hChild, GetLastError());
00356 return false;
00357 }
00358 if (address != UsedShmemSegAddr)
00359 {
00360
00361
00362
00363
00364
00365
00366 elog(LOG, "reserved shared memory region got incorrect address %p, expected %p",
00367 address, UsedShmemSegAddr);
00368 VirtualFreeEx(hChild, address, 0, MEM_RELEASE);
00369 return false;
00370 }
00371
00372 return true;
00373 }