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

Commit4fe384b

Browse files
committed
Process 'die' interrupts while reading/writing from the client socket.
Up to now it was impossible to terminate a backend that was trying tosend/recv data to/from the client when the socket's buffer was alreadyfull/empty. While the send/recv calls itself might have gotteninterrupted by signals on some platforms, we just immediately retried.That could lead to situations where a backend couldn't be terminated ,after a client died without the connection being closed, because itwas blocked in send/recv.The problem was far more likely to be hit when sending data than whenreading. That's because while reading a command from the client, andduring authentication, we processed interrupts immediately . Thatprimarily left COPY FROM STDIN as being problematic for recv.Change things so that that we process 'die' events immediately whenthe appropriate signal arrives. We can't sensibly react to querycancels at that point, because we might loose sync with the client aswe could be in the middle of writing a message.We don't interrupt writes if the write buffer isn't full, as indicatedby write() returning EWOULDBLOCK, as that would lead to fewer errormessages reaching clients.Per discussion with Kyotaro HORIGUCHI and Heikki LinnakangasDiscussion: 20140927191243.GD5423@alap3.anarazel.de
1 parent4f85fde commit4fe384b

File tree

4 files changed

+105
-30
lines changed

4 files changed

+105
-30
lines changed

‎src/backend/libpq/be-secure-openssl.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ be_tls_read(Port *port, void *ptr, size_t len)
553553
if (latchret&WL_LATCH_SET)
554554
{
555555
ResetLatch(MyLatch);
556-
ProcessClientReadInterrupt();/* preserves errno */
556+
ProcessClientReadInterrupt(true);/* preserves errno */
557557
}
558558
gotorloop;
559559
caseSSL_ERROR_SYSCALL:
@@ -595,6 +595,7 @@ be_tls_write(Port *port, void *ptr, size_t len)
595595
ssize_tn;
596596
interr;
597597
intwaitfor;
598+
intlatchret;
598599

599600
/*
600601
* If SSL renegotiations are enabled and we're getting close to the
@@ -659,16 +660,27 @@ be_tls_write(Port *port, void *ptr, size_t len)
659660
caseSSL_ERROR_WANT_READ:
660661
caseSSL_ERROR_WANT_WRITE:
661662

663+
waitfor=WL_LATCH_SET;
664+
662665
if (err==SSL_ERROR_WANT_READ)
663-
waitfor=WL_SOCKET_READABLE;
666+
waitfor|=WL_SOCKET_READABLE;
664667
else
665-
waitfor=WL_SOCKET_WRITEABLE;
668+
waitfor |=WL_SOCKET_WRITEABLE;
669+
670+
latchret=WaitLatchOrSocket(MyLatch,waitfor,port->sock,0);
666671

667-
WaitLatchOrSocket(MyLatch,waitfor,port->sock,0);
668672
/*
669-
* XXX: We'll, at some later point, likely want to add interrupt
670-
* processing here.
673+
* Check for interrupts here, in addition to secure_write(),
674+
* because an interrupted write in secure_raw_write() will return
675+
* here, and we cannot return to secure_write() until we've
676+
* written something.
671677
*/
678+
if (latchret&WL_LATCH_SET)
679+
{
680+
ResetLatch(MyLatch);
681+
ProcessClientWriteInterrupt(true);/* preserves errno */
682+
}
683+
672684
gotowloop;
673685
caseSSL_ERROR_SYSCALL:
674686
/* leave it to caller to ereport the value of errno */

‎src/backend/libpq/be-secure.c

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,27 @@ secure_read(Port *port, void *ptr, size_t len)
140140
n=secure_raw_read(port,ptr,len);
141141
}
142142

143-
/* Process interrupts that happened while (or before) receiving. */
144-
ProcessClientReadInterrupt();/* preserves errno */
145-
146143
/* retry after processing interrupts */
147144
if (n<0&&errno==EINTR)
148145
{
146+
/*
147+
* We tried to read data, the socket was empty, and we were
148+
* interrupted while waiting for readability. We only process
149+
* interrupts if we got interrupted while reading and when in blocking
150+
* mode. In other cases it's better to allow the interrupts to be
151+
* handled at higher layers.
152+
*/
153+
ProcessClientReadInterrupt(!port->noblock);/* preserves errno */
149154
gotoretry;
150155
}
156+
157+
/*
158+
* Process interrupts that happened while (or before) receiving. Note that
159+
* we signal that we're not blocking, which will prevent some types of
160+
* interrupts from being processed.
161+
*/
162+
ProcessClientReadInterrupt(false);
163+
151164
returnn;
152165
}
153166

@@ -224,18 +237,17 @@ secure_write(Port *port, void *ptr, size_t len)
224237
n=secure_raw_write(port,ptr,len);
225238
}
226239

227-
/*
228-
* XXX: We'll, at some later point, likely want to add interrupt
229-
* processing here.
230-
*/
231-
232-
/*
233-
* Retry after processing interrupts. This can be triggered even though we
234-
* don't check for latch set's during writing yet, because SSL
235-
* renegotiations might have required reading from the socket.
236-
*/
240+
/* retry after processing interrupts */
237241
if (n<0&&errno==EINTR)
238242
{
243+
/*
244+
* We tried to send data, the socket was full, and we were interrupted
245+
* while waiting for writability. We only process interrupts if we got
246+
* interrupted while writing and when in blocking mode. In other cases
247+
* it's better to allow the interrupts to be handled at higher layers.
248+
*/
249+
ProcessClientWriteInterrupt(!port->noblock);
250+
239251
gotoretry;
240252
}
241253

@@ -262,17 +274,21 @@ secure_raw_write(Port *port, const void *ptr, size_t len)
262274
intw;
263275
intsave_errno=errno;
264276

265-
/*
266-
* We probably want to check for latches being set at some point
267-
* here. That'd allow us to handle interrupts while blocked on
268-
* writes. If set we'd not retry directly, but return. That way we
269-
* don't do anything while (possibly) inside a ssl library.
270-
*/
271277
w=WaitLatchOrSocket(MyLatch,
272-
WL_SOCKET_WRITEABLE,
278+
WL_LATCH_SET |WL_SOCKET_WRITEABLE,
273279
port->sock,0);
274280

275-
if (w&WL_SOCKET_WRITEABLE)
281+
if (w&WL_LATCH_SET)
282+
{
283+
ResetLatch(MyLatch);
284+
/*
285+
* Force a return, so interrupts can be processed when not
286+
* (possibly) underneath a ssl library.
287+
*/
288+
errno=EINTR;
289+
return-1;
290+
}
291+
elseif (w&WL_SOCKET_WRITEABLE)
276292
{
277293
gotowloop;
278294
}

‎src/backend/tcop/postgres.c

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ interactive_getc(void)
318318

319319
c=getc(stdin);
320320

321-
ProcessClientReadInterrupt();
321+
ProcessClientReadInterrupt(true);
322322

323323
returnc;
324324
}
@@ -529,7 +529,7 @@ ReadCommand(StringInfo inBuf)
529529
* Must preserve errno!
530530
*/
531531
void
532-
ProcessClientReadInterrupt(void)
532+
ProcessClientReadInterrupt(boolblocked)
533533
{
534534
intsave_errno=errno;
535535

@@ -546,10 +546,56 @@ ProcessClientReadInterrupt(void)
546546
if (notifyInterruptPending)
547547
ProcessNotifyInterrupt();
548548
}
549+
elseif (ProcDiePending&&blocked)
550+
{
551+
/*
552+
* We're dying. It's safe (and sane) to handle that now.
553+
*/
554+
CHECK_FOR_INTERRUPTS();
555+
}
549556

550557
errno=save_errno;
551558
}
552559

560+
/*
561+
* ProcessClientWriteInterrupt() - Process interrupts specific to client writes
562+
*
563+
* This is called just after low-level writes. That might be after the read
564+
* finished successfully, or it was interrupted via interrupt. 'blocked' tells
565+
* us whether the
566+
*
567+
* Must preserve errno!
568+
*/
569+
void
570+
ProcessClientWriteInterrupt(boolblocked)
571+
{
572+
intsave_errno=errno;
573+
574+
Assert(InterruptHoldoffCount==0&&CritSectionCount==0);
575+
576+
/*
577+
* We only want to process the interrupt here if socket writes are
578+
* blocking to increase the chance to get an error message to the
579+
* client. If we're not blocked there'll soon be a
580+
* CHECK_FOR_INTERRUPTS(). But if we're blocked we'll never get out of
581+
* that situation if the client has died.
582+
*/
583+
if (ProcDiePending&&blocked)
584+
{
585+
/*
586+
* We're dying. It's safe (and sane) to handle that now. But we don't
587+
* want to send the client the error message as that a) would possibly
588+
* block again b) would possibly lead to sending an error message to
589+
* the client, while we already started to send something else.
590+
*/
591+
if (whereToSendOutput==DestRemote)
592+
whereToSendOutput=DestNone;
593+
594+
CHECK_FOR_INTERRUPTS();
595+
}
596+
597+
errno=save_errno;
598+
}
553599

554600
/*
555601
* Do raw parsing (only).

‎src/include/tcop/tcopprot.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ extern void StatementCancelHandler(SIGNAL_ARGS);
6767
externvoidFloatExceptionHandler(SIGNAL_ARGS) __attribute__((noreturn));
6868
externvoidRecoveryConflictInterrupt(ProcSignalReasonreason);/* called from SIGUSR1
6969
* handler */
70-
externvoidProcessClientReadInterrupt(void);
70+
externvoidProcessClientReadInterrupt(boolblocked);
71+
externvoidProcessClientWriteInterrupt(boolblocked);
7172

7273
externvoidprocess_postgres_switches(intargc,char*argv[],
7374
GucContextctx,constchar**dbname);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp