Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite2f0f8e

Browse files
committed
Check for STATUS_DELETE_PENDING on Windows.
1. Update our open() wrapper to check for NT's STATUS_DELETE_PENDINGand translate it to Unix-like errors. This is done withRtlGetLastNtStatus(), which is dynamically loaded from ntdll. A newfile win32ntdll.c centralizes lookup of NT functions, in case we decideto add more in the future.2. Remove non-working code that was trying to do something similar forstat(), and just reuse the open() wrapper code. As a side effect,stat() also gains resilience against "sharing violation" errors.3. Since stat() is used very early in process startup, remove therequirement that the Win32 signal event has been created beforepgwin32_open_handle() is reached. Instead, teach pg_usleep() to fallback to a non-interruptible sleep if reached before the signal event isavailable.This could be back-patched, but for now it's in master only. Theproblem has apparently been with us for a long time and generated only afew complaints. Proposed patches trigger it more often, which led tothis investigation and fix.Reviewed-by: Andres Freund <andres@anarazel.de>Reviewed-by: Alexander Lakhin <exclusion@gmail.com>Reviewed-by: Juan José Santamaría Flecha <juanjo.santamaria@gmail.com>Discussion:https://postgr.es/m/CA%2BhUKGJz_pZTF9mckn6XgSv69%2BjGwdgLkxZ6b3NWGLBCVjqUZA%40mail.gmail.com
1 parent5d08137 commite2f0f8e

File tree

9 files changed

+178
-209
lines changed

9 files changed

+178
-209
lines changed

‎configure

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16738,6 +16738,12 @@ esac
1673816738
;;
1673916739
esac
1674016740

16741+
case " $LIBOBJS " in
16742+
*" win32ntdll.$ac_objext "* ) ;;
16743+
*) LIBOBJS="$LIBOBJS win32ntdll.$ac_objext"
16744+
;;
16745+
esac
16746+
1674116747
case " $LIBOBJS " in
1674216748
*" win32security.$ac_objext "* ) ;;
1674316749
*) LIBOBJS="$LIBOBJS win32security.$ac_objext"

‎configure.ac

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1932,6 +1932,7 @@ if test "$PORTNAME" = "win32"; then
19321932
AC_LIBOBJ(system)
19331933
AC_LIBOBJ(win32env)
19341934
AC_LIBOBJ(win32error)
1935+
AC_LIBOBJ(win32ntdll)
19351936
AC_LIBOBJ(win32security)
19361937
AC_LIBOBJ(win32setlocale)
19371938
AC_LIBOBJ(win32stat)

‎src/backend/port/win32/signal.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,17 @@ static BOOL WINAPI pg_console_handler(DWORD dwCtrlType);
5252
void
5353
pg_usleep(longmicrosec)
5454
{
55-
Assert(pgwin32_signal_event!=NULL);
55+
if (unlikely(pgwin32_signal_event==NULL))
56+
{
57+
/*
58+
* If we're reached by pgwin32_open_handle() early in startup before
59+
* the signal event is set up, just fall back to a regular
60+
* non-interruptible sleep.
61+
*/
62+
SleepEx((microsec<500 ?1 : (microsec+500) /1000), FALSE);
63+
return;
64+
}
65+
5666
if (WaitForSingleObject(pgwin32_signal_event,
5767
(microsec<500 ?1 : (microsec+500) /1000))
5868
==WAIT_OBJECT_0)

‎src/include/port.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ extern bool rmtree(const char *path, bool rmtopdir);
296296
* passing of other special options.
297297
*/
298298
#defineO_DIRECT0x80000000
299+
externHANDLEpgwin32_open_handle(constchar*,int,bool);
299300
externintpgwin32_open(constchar*,int,...);
300301
externFILE*pgwin32_fopen(constchar*,constchar*);
301302
#defineopen(a,b,c) pgwin32_open(a,b,c)

‎src/include/port/win32ntdll.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* win32ntdll.h
4+
* Dynamically loaded Windows NT functions.
5+
*
6+
* Portions Copyright (c) 2021, PostgreSQL Global Development Group
7+
* Portions Copyright (c) 1994, Regents of the University of California
8+
*
9+
* src/include/port/win32ntdll.h
10+
*
11+
*-------------------------------------------------------------------------
12+
*/
13+
14+
/*
15+
* Because this includes NT headers that normally conflict with Win32 headers,
16+
* any translation unit that includes it should #define UMDF_USING_NTSTATUS
17+
* before including <windows.h>.
18+
*/
19+
20+
#include<ntstatus.h>
21+
#include<winternl.h>
22+
23+
typedefNTSTATUS (__stdcall*RtlGetLastNtStatus_t) (void);
24+
25+
externRtlGetLastNtStatus_tpg_RtlGetLastNtStatus;
26+
27+
externintinitialize_ntdll(void);

‎src/port/open.c

Lines changed: 56 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,20 @@
1313

1414
#ifdefWIN32
1515

16+
#defineUMDF_USING_NTSTATUS
17+
1618
#ifndefFRONTEND
1719
#include"postgres.h"
1820
#else
1921
#include"postgres_fe.h"
2022
#endif
2123

24+
#include"port/win32ntdll.h"
25+
2226
#include<fcntl.h>
2327
#include<assert.h>
2428
#include<sys/stat.h>
2529

26-
2730
staticint
2831
openFlagsToCreateFileFlags(intopenFlags)
2932
{
@@ -56,38 +59,25 @@ openFlagsToCreateFileFlags(int openFlags)
5659
}
5760

5861
/*
59-
* - file attribute setting, based on fileMode?
62+
* Internal function used by pgwin32_open() and _pgstat64(). When
63+
* backup_semantics is true, directories may be opened (for limited uses). On
64+
* failure, INVALID_HANDLE_VALUE is returned and errno is set.
6065
*/
61-
int
62-
pgwin32_open(constchar*fileName,intfileFlags,...)
66+
HANDLE
67+
pgwin32_open_handle(constchar*fileName,intfileFlags,boolbackup_semantics)
6368
{
64-
intfd;
65-
HANDLEh=INVALID_HANDLE_VALUE;
69+
HANDLEh;
6670
SECURITY_ATTRIBUTESsa;
6771
intloops=0;
6872

73+
if (initialize_ntdll()<0)
74+
returnINVALID_HANDLE_VALUE;
75+
6976
/* Check that we can handle the request */
7077
assert((fileFlags& ((O_RDONLY |O_WRONLY |O_RDWR) |O_APPEND |
7178
(O_RANDOM |O_SEQUENTIAL |O_TEMPORARY) |
7279
_O_SHORT_LIVED |O_DSYNC |O_DIRECT |
7380
(O_CREAT |O_TRUNC |O_EXCL) | (O_TEXT |O_BINARY)))==fileFlags);
74-
#ifndefFRONTEND
75-
Assert(pgwin32_signal_event!=NULL);/* small chance of pg_usleep() */
76-
#endif
77-
78-
#ifdefFRONTEND
79-
80-
/*
81-
* Since PostgreSQL 12, those concurrent-safe versions of open() and
82-
* fopen() can be used by frontends, having as side-effect to switch the
83-
* file-translation mode from O_TEXT to O_BINARY if none is specified.
84-
* Caller may want to enforce the binary or text mode, but if nothing is
85-
* defined make sure that the default mode maps with what versions older
86-
* than 12 have been doing.
87-
*/
88-
if ((fileFlags&O_BINARY)==0)
89-
fileFlags |=O_TEXT;
90-
#endif
9181

9282
sa.nLength=sizeof(sa);
9383
sa.bInheritHandle= TRUE;
@@ -102,6 +92,7 @@ pgwin32_open(const char *fileName, int fileFlags,...)
10292
&sa,
10393
openFlagsToCreateFileFlags(fileFlags),
10494
FILE_ATTRIBUTE_NORMAL |
95+
(backup_semantics ?FILE_FLAG_BACKUP_SEMANTICS :0) |
10596
((fileFlags&O_RANDOM) ?FILE_FLAG_RANDOM_ACCESS :0) |
10697
((fileFlags&O_SEQUENTIAL) ?FILE_FLAG_SEQUENTIAL_SCAN :0) |
10798
((fileFlags&_O_SHORT_LIVED) ?FILE_ATTRIBUTE_TEMPORARY :0) |
@@ -140,38 +131,55 @@ pgwin32_open(const char *fileName, int fileFlags,...)
140131
/*
141132
* ERROR_ACCESS_DENIED is returned if the file is deleted but not yet
142133
* gone (Windows NT status code is STATUS_DELETE_PENDING). In that
143-
* case we want to wait a bit and try again, giving up after 1 second
144-
* (since this condition should never persist very long). However,
145-
* there are other commonly-hit cases that return ERROR_ACCESS_DENIED,
146-
* so care is needed. In particular that happens if we try to open a
147-
* directory, or of course if there's an actual file-permissions
148-
* problem. To distinguish these cases, try a stat(). In the
149-
* delete-pending case, it will either also get STATUS_DELETE_PENDING,
150-
* or it will see the file as gone and fail with ENOENT. In other
151-
* cases it will usually succeed. The only somewhat-likely case where
152-
* this coding will uselessly wait is if there's a permissions problem
153-
* with a containing directory, which we hope will never happen in any
154-
* performance-critical code paths.
134+
* case, we'd better ask for the NT status too so we can translate it
135+
* to a more Unix-like error. We hope that nothing clobbers the NT
136+
* status in between the internal NtCreateFile() call and CreateFile()
137+
* returning.
138+
*
139+
* If there's no O_CREAT flag, then we'll pretend the file is
140+
* invisible. With O_CREAT, we have no choice but to report that
141+
* there's a file in the way (which wouldn't happen on Unix).
155142
*/
156-
if (err==ERROR_ACCESS_DENIED)
143+
if (err==ERROR_ACCESS_DENIED&&
144+
pg_RtlGetLastNtStatus()==STATUS_DELETE_PENDING)
157145
{
158-
if (loops<10)
159-
{
160-
structstatst;
161-
162-
if (stat(fileName,&st)!=0)
163-
{
164-
pg_usleep(100000);
165-
loops++;
166-
continue;
167-
}
168-
}
146+
if (fileFlags&O_CREAT)
147+
err=ERROR_FILE_EXISTS;
148+
else
149+
err=ERROR_FILE_NOT_FOUND;
169150
}
170151

171152
_dosmaperr(err);
172-
return-1;
153+
returnINVALID_HANDLE_VALUE;
173154
}
174155

156+
returnh;
157+
}
158+
159+
int
160+
pgwin32_open(constchar*fileName,intfileFlags,...)
161+
{
162+
HANDLEh;
163+
intfd;
164+
165+
h=pgwin32_open_handle(fileName,fileFlags, false);
166+
if (h==INVALID_HANDLE_VALUE)
167+
return-1;
168+
169+
#ifdefFRONTEND
170+
171+
/*
172+
* Since PostgreSQL 12, those concurrent-safe versions of open() and
173+
* fopen() can be used by frontends, having as side-effect to switch the
174+
* file-translation mode from O_TEXT to O_BINARY if none is specified.
175+
* Caller may want to enforce the binary or text mode, but if nothing is
176+
* defined make sure that the default mode maps with what versions older
177+
* than 12 have been doing.
178+
*/
179+
if ((fileFlags&O_BINARY)==0)
180+
fileFlags |=O_TEXT;
181+
#endif
182+
175183
/* _open_osfhandle will, on error, set errno accordingly */
176184
if ((fd=_open_osfhandle((intptr_t)h,fileFlags&O_APPEND))<0)
177185
CloseHandle(h);/* will not affect errno */

‎src/port/win32ntdll.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* win32ntdll.c
4+
* Dynamically loaded Windows NT functions.
5+
*
6+
* Portions Copyright (c) 2021, PostgreSQL Global Development Group
7+
* Portions Copyright (c) 1994, Regents of the University of California
8+
*
9+
*
10+
* IDENTIFICATION
11+
* src/port/win32ntdll.c
12+
*
13+
*-------------------------------------------------------------------------
14+
*/
15+
16+
#defineUMDF_USING_NTSTATUS
17+
18+
#include"c.h"
19+
20+
#include"port/win32ntdll.h"
21+
22+
RtlGetLastNtStatus_tpg_RtlGetLastNtStatus;
23+
24+
typedefstructNtDllRoutine
25+
{
26+
constchar*name;
27+
pg_funcptr_t*address;
28+
}NtDllRoutine;
29+
30+
staticconstNtDllRoutineroutines[]= {
31+
{"RtlGetLastNtStatus", (pg_funcptr_t*)&pg_RtlGetLastNtStatus}
32+
};
33+
34+
staticboolinitialized;
35+
36+
int
37+
initialize_ntdll(void)
38+
{
39+
HMODULEmodule;
40+
41+
if (initialized)
42+
return0;
43+
44+
if (!(module=LoadLibraryEx("ntdll.dll",NULL,0)))
45+
{
46+
_dosmaperr(GetLastError());
47+
return-1;
48+
}
49+
50+
for (inti=0;i<lengthof(routines);++i)
51+
{
52+
pg_funcptr_taddress;
53+
54+
address= (pg_funcptr_t)GetProcAddress(module,routines[i].name);
55+
if (!address)
56+
{
57+
_dosmaperr(GetLastError());
58+
FreeLibrary(module);
59+
60+
return-1;
61+
}
62+
63+
*(pg_funcptr_t*)routines[i].address=address;
64+
}
65+
66+
initialized= true;
67+
68+
return0;
69+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp