[Haskell-cafe] Killing threads in foreign calls.
Edward Z. Yang
ezyang at MIT.EDU
Sun Apr 17 22:26:54 CEST 2011
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/Database-PQ.html#exec
>
> 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/Database-PQ.html#line-2222
>
> 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.
>
More information about the Haskell-Cafe
mailing list