SQLite

View Ticket
Login
Ticket Hash: 2c5661c26a0c1b50e083af7110001267b934d912
Title: Thread safety: does SQLite handle pthread_cancel cleanly?
Status: Closed Type: Feature_Request
Severity: Important Priority: Immediate
Subsystem: Other Resolution: Rejected
Last Modified: 2014-03-11 12:56:01
11.28 years ago
Created: 2009-08-24 05:53:27
15.82 years ago
Version Found In: 3.6.17
Description:
While fixing a threaded server application that uses sqlite3, I've notice that sometimes the application crashes during termination in sqlite functions depending on the timing of thread termination using pthread_cancel(). It is unclear to me whether sqlite takes pthread_cancel into consideration, so I thought to raise this ticket for future consideration, since I myself have been neglect until recently concerning issues with pthread_cancel.

There are issues of concern related to pthread_cancel that I've come across recently:

1. Calling pthread_cancel while a thread has a mutex locked, can cause other threads to deadlock. On OpenBSD (and probably Linux) pthread_cond_wait is a cancellation point, which means:

pthread_lock(&mutex) while (condition not true) pthread_cond_wait(&cond_var, &mutex) pthread_unlock(&mutex)

Could result in the thread terminating while blocked on a conditional variable with mutex locked. I've found the following idiom useful:

pthread_mutex_lock(&mutex) pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock, &mutex) while (condition not true) pthread_cond_wait(&cond_var, &mutex) pthread_cleanup_pop(1)

in order to guarantee that the mutex is released when the thread terminates due to pthread_cancel. The use of pthread_cleanup_push / pop should probably be used any place that mutex lock/unlock protects a complex region of code, not just the case of conditional variables. OpenBSD documents their cancellation points, while Linux does not.

From OpenBSD 4.0 man pthread_testcancel

Cancellation Points Cancellation points will occur when a thread is executing the following functions: close(), creat(), fcntl(), fsync(), msync(), nanosleep(), open(), pause(), pthread_cond_timedwait(), pthread_cond_wait(), pthread_join(), pthread_testcancel(), read(), sigwaitinfo(), sigsuspend(), sigwait(), sleep(), system(), tcdrain(), wait(), waitpid(), write().

2. Calling pthread_cancel while a thread is performing critical functions. If pthread_cleanup_push/pop are not suitable, then consider deferring thread cancellation around complex sections of code:

int old_state; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state); ...long complex series of operations, like file IO... pthread_setcancelstate(old_state, NULL);

I've found in my own code, in order to avoid potential problems related to pthread_cancel, that wrapping calls to sqlite3_exec, sqlite3_step, sqlite3_close appears to reduce, if not eliminate potential crashes and/or corruption.

3. Another possible issue of concern pthread_setcanceltype, similar to pthread_setcancelstate, which can be set to deferred or asynchronous by the calling application. Library functions that temporarily disable cancellation probably need not worry. I raise the point only for consideration.