Re: Interrupting long external library calls

Поиск
Список
Период
Сортировка
От Florian Pflug
Тема Re: Interrupting long external library calls
Дата
Msg-id FB27B9B7-CE47-4675-91D7-0D6161548B5D@phlo.org
обсуждение исходный текст
Ответ на Re: Interrupting long external library calls  (Sandro Santilli <strk@keybit.net>)
Ответы Re: Interrupting long external library calls  (Sandro Santilli <strk@keybit.net>)
Список pgsql-hackers
On May24, 2012, at 15:04 , Sandro Santilli wrote:
> On Wed, May 16, 2012 at 07:30:03PM +0300, Heikki Linnakangas wrote:
>> On 16.05.2012 15:42, Sandro Santilli wrote:
>>> But CHECK_FOR_INTERRUPTS doesn't return, right ?
>>> Is there another macro for just checking w/out yet acting upon it ?
>>
>> Hmm, no. CHECK_FOR_INTERRUPTS() checks the InterruptPending
>> variable, but on Windows it also checks for
>> UNBLOCKED_SIGNAL_QUEUE(). And even if InterruptPending is set, it's
>> not totally certain that CHECK_FOR_INTERRUPTS() won't return. I
>> think InterruptPending can be set spuriously (even if that's not
>> possible today, I wouldn't rely on it), and if you're in a
>> HOLD/RESUME_INTERRUPTS block, CHECK_FOR_INTERRUPTS() will do nothing
>> even if InterruptPending is true.
>>
>> The only sane way to make 3rd party code interruptible is to add
>> CHECK_FOR_INTERRUPTS() to it, in safe places.
>
> No place is safe if CHECK_FOR_INTERRUPTS doesn't return.
> How could caller code cleanup on interruption ?

The postgres way is to use PG_TRY/PG_CATCH to make sure stuff gets cleaned
up if an error or an interrupts occurs. You could use those to make the
third-party library exception safe, but it'll probably be a quite
invasive change :-(.

Alternatively, you could replicate the check CHECK_FOR_INTERRUPTS() does,
but then don't actually call ProcessInterrupts() but instead just make
the third-party code abort signalling an error, and call
CHECK_FOR_INTERRUPTS() after the third-party code has returned. On unix-like
systems that'd be a simple as aborting if InterruptPending is set, while
on windows you'd have to do the if(UNBLOCKED_SIGNAL_QUEUE())… stuff first,
since otherwise InterruptPending will never get set. The following function
should do the trick
 bool have_pending_interrupts() { #ifdef WIN32   if (UNBLOCKED_SIGNAL_QUEUE())     pgwin32_dispatch_queued_signals();
#endif
   return InterruptPending && !InterruptHoldoffCount && !CritSectionCount; }

The third-party could would then do
 if (have_pending_interrupts())   return some_error;

and you'd invoke in with
 state = third_party_code(); CHECK_FOR_INTERRUPTS(); if (state != success)   ereport(…);

There might be slim chance for false positives with that approach, since
ProcessInterrupts() might not always ereport(), even if InterruptHoldoffCount
and CritSectionCount are zero. But they'll simply get turned into spurious
ereport() by the if(state != success) check after CHECK_FOR_INTERRUPTS, and
should be very rare, and happen only shortly after a query cancel request
was received.

best regards,
Florian Pflug



В списке pgsql-hackers по дате отправления:

Предыдущее
От: Tom Lane
Дата:
Сообщение: Re: shared_preload_libraries path
Следующее
От: Magnus Hagander
Дата:
Сообщение: Re: pg_stat_statments queryid