Killing threads in foreign calls.

I am building an application that uses Postgres for storage. If a query runs too long, I would like to kill the querying thread, releasing its lock on the connection; if the connection is a in a bad state -- for example, busy -- I would like to clean up the connection. Unfortunately, killing calls in to libpq seems not to work. I have put a minimal example on hpaste: http://hpaste.org/45774/minimal_pg_contention_example If you install libpq with Cabal, you can run it. In the example, the main thread spawns a worker thread that queries Postgres, running "SELECT pg_sleep(10);"; the main thread waits half a second and then tries to kill the worker. Unfortunately, the worker always manages to get as far as printing "complete". In the code, I call `Database.PQ.exec': http://hackage.haskell.org/packages/archive/libpq/0.4.1/doc/html/src/Databas... This in turn calls a `safe' binding, `c_PQexec', to `PQexec' in the C library: http://hackage.haskell.org/packages/archive/libpq/0.4.1/doc/html/src/Databas... There are async interfaces, too; they do not seem to be any more killable then the sync ones. Maybe the problem is that you can't kill a thread while it's in a foreign call? I do not see any documentation to this effect; but I may have missed it. -- Jason Dusek () ascii ribbon campaign - against html e-mail /\ www.asciiribbon.org - against proprietary attachments

This is a fairly nontrivial problem. First off, let me tell you what you do not /actually/ want to happen: you don't want the OS level thread performing the foreign call to actually be killed; most C code is not written a way that can gracefully recover from this, and unless you have explicit indications from the Postgres library that it use pthread_setcancelstate (and you, of course, have the cross-platform issue.) You need some way of making the Postgres call return early, with an error code of some sort. If Postgres has a signal handler that does this, you can use something along the lines of here: http://blog.ezyang.com/2010/11/its-just-a-longjmp-to-the-left/ If the asynchronous API has the ability to cancel a query given some handler, you instead want to set up a custom kill thread function that checks if a thread has an active query and then performs another FFI call to perform that cancellation. If the library doesn't have a way of doing graceful cancellation, you're kind of out of luck. Unfortunately there is no golden touch for making this work. Cheers, Edward Excerpts from Jason Dusek's message of Sun Apr 17 15:31:11 -0400 2011:
I am building an application that uses Postgres for storage. If a query runs too long, I would like to kill the querying thread, releasing its lock on the connection; if the connection is a in a bad state -- for example, busy -- I would like to clean up the connection.
Unfortunately, killing calls in to libpq seems not to work. I have put a minimal example on hpaste:
http://hpaste.org/45774/minimal_pg_contention_example
If you install libpq with Cabal, you can run it. In the example, the main thread spawns a worker thread that queries Postgres, running "SELECT pg_sleep(10);"; the main thread waits half a second and then tries to kill the worker. Unfortunately, the worker always manages to get as far as printing "complete".
In the code, I call `Database.PQ.exec':
http://hackage.haskell.org/packages/archive/libpq/0.4.1/doc/html/src/Databas...
This in turn calls a `safe' binding, `c_PQexec', to `PQexec' in the C library:
http://hackage.haskell.org/packages/archive/libpq/0.4.1/doc/html/src/Databas...
There are async interfaces, too; they do not seem to be any more killable then the sync ones.
Maybe the problem is that you can't kill a thread while it's in a foreign call? I do not see any documentation to this effect; but I may have missed it.

On Sun, Apr 17, 2011 at 20:26, Edward Z. Yang
This is a fairly nontrivial problem. First off, let me tell you what you do not /actually/ want to happen: you don't want the OS level thread performing the foreign call to actually be killed...
From this I gather, one can not generally kill Haskell threads while they are in the midst of foreign calls. I guess interrupting execution to terminate the program is special since you don't expect anything to work properly afterward.
If the asynchronous API has the ability to cancel a query given some handler, you instead want to set up a custom kill thread function that checks if a thread has an active query and then performs another FFI call to perform that cancellation.
It turns out the PGcancel exists for this purpose. Is it safe and reasonable to make query cancellation a ThreadKilled handler in the query thread? I gather I need to write the busy loop for polling for data in Haskell. Although libpq has a procedure -- PGgetResult -- that polls for data, it would not respond to killThread. -- Jason Dusek () ascii ribbon campaign - against html e-mail /\ www.asciiribbon.org - against proprietary attachments

On Mon, Apr 18, 2011 at 12:48 AM, Jason Dusek
I gather I need to write the busy loop for polling for data in Haskell. Although libpq has a procedure -- PGgetResult -- that polls for data, it would not respond to killThread.
Please don't use a busy loop! Instead use PQSocket() to get the
underlying socket file descriptor, and call
ThreadWaitRead/ThreadWaitWrite to use the system event dispatcher
(epoll() or select()) to efficiently multiplex.
G
--
Gregory Collins
participants (3)
-
Edward Z. Yang
-
Gregory Collins
-
Jason Dusek