[freetds] dblib and thread safety

ZIGLIO, Frediano, VF-IT Frediano.Ziglio at vodafone.com
Fri Sep 24 05:35:22 EDT 2004

> > I see. However tds_ctx it's referenced in TDSSOCKET and 
> used (only for
> > reading) in all libTDS functions. So you have active readed 
> structures
> Whether or not it's used for reading or writing is not relevant. The
> concern here is memory visibility, not mutual exclusion.

I don't follow you...

> > while you have connections. If you call dbexit dblib free all
> > connections so you "release" all pointers and you can safely delete
> > context. In dbinit you allocate context so only dbinit can 
> write to this
> > context, it's not useful to initialize context inside the 
> mutex. Perhaps
> > we should check for no connections inside dbinit. It's an 
> error to call
> Actually, I thought about this too. My solution would be to 
> use pthread_once() 
> to ensure that dbinit() is only ever called once. 
> This could also be achieved with a global flag (inside 
> g_dblib_ctx) and a 
> mutex if you wanted to make that same functionality available 
> without threads 
> enabled (probably a good idea).
> > dbinit after another dbinit. It's also a programmer error 
> to call dbinit
> > while another dblib function it's called... I used no 
> recursive mutex
> Indeed, but I think we should guard for it anyway.

Well Liam, perhaps it seems I'm disappointing your patch. I'd like to
bring all FreeTDS to full thread-safe however we are releasing a new
version so CVS it's not so bleeding edge so any change require a lot of
attention. thread support it's not so easily portable so it require a
lot of attentions. Using mutex for every context use can slow down some
application very much (think about a apache web server in thread mode
using PHP) so this it's the reason I don't like to put a mutex here.
Thing are going to change at branch but we have a small stuff so a
branch cast us a lot of time (Linux kernel follows 4 release we hardly
follow 2, CVS and stable).

> > cause are faster and cause my code don't need recursive one (if we
> > require recursive one I have to change configure too). 
> tds_convert use
> Please don't get me wrong, I don't like using the recursive 
> mutex for this 
> patch as much as you do but without a major re-write there is 
> no other way 
> I can see to guarantee thread safety in that section of code.
> In the context of something that communicates over TCP/IP sockets, I
> also don't think the extra nano-second it takes to process a 
> recursive 
> mutex is worth discussing.

Even here while pthread no-recursive mutex initializer are portable
pthread recursive initializer it's not so it require more configure
script, for systems that do not have pthread recursive initializer we
should use pthread_once and this require other configure stuff and
others tests.

> > every processor I know can read memory in a single 
> instruction. It's not
> > useful to use mutex here. Better to use volatile to disallow strange
> > optmizations.
> Wrong, wrong, wrong.
> What if the other CPU (in a multi-processor computer) changes 
> the value at 
> the exact same instant in time as the read with the same 
> atomic instruction?
> You are also ignoring the effect of the TLB and cache.

You are right... time ago someone enlight me with this problem but I
don't find any solution... what happen here? Does processor have to
flush data for every mutex operation??

I don't think however that reading a variable inside a mutex and
returning it help... Just after the mutex and before returning another
thread (even on single processor) can change value.... but perhaps the
code in dbopen (that read both variable) require it... Well, I don't see
any problem adding these mutex...

> Please see:

Here we are speaking of increment a variable, that is read and write,
mutex it's required. This do not apply to our case

> If you want to argue with me that's fine, but don't argue with Bil
> and David Butenhof, both of whom are the authors of the most respected
> texts on threads.

Very good text. However it speaks about C99... FreeTDS require just ANSI
C, I found many compiler that are not C99 and really require volatile to
avoid optimization.

Just consider this code

volatile int check = 0;

void wait_check()
	while (!check)

Well... it's indead a bad code however if check it's changed in another
thread to 1 wait_check returns. Removing volatile here can cause an
infinite loop. For example gcc 3.x gave this problem (if I remember was
3.2... not that old).

> I've programmed with threads for close to 5 years and have published
> several papers on subject. I am very keen to get FreeTDS working
> for my project and I don't want to have a long discussion on threads 
> programming. 
> Please, cut me some slack and let's get down to the business of making
> dblib thread safe! :)

Perhaps the problem it's that dblib it's not thread-safe. Honestly I
don't know dblib that much... however I would consider dbexit no that
thread-safe... It's very expensive to take it to thread-safe...

> > For full thread safe for context you have to prevent a thread inside
> > dblib call and call to dbexit... however I don't know a solution for
> > this... use a rw lock in every dblib ?
> I still don't understand why we can not put a per-connection tds_ctx
> every individual DBPROCESS structure? I am no where near as familiar
with the
> internals of TDS as you are so is there some reason why you do not
want to
> do this?

Why do you want to duplicate a constant structure?? It's only changed in
dbexit and as said you shouldn't consider dbexit as thread-safe...

> Thanks for your help on this to date.
> Cheers.

If your program do not load and unload dblibrary at runtime I would
avoid to call dbexit and take connection list thread-safe. This should
solve all your thread-safe problems. This do not require recursive mutex
and other strange stuff...

Another objection it's cancelling. As said in FAQ FreeTDS should be
connection thread-safe. That is if a connection it's used only in a
thread FreeTDS should be considered thread-safe. However each library
(dblib, ctlib and ODBC) require that cancel can be called from another
thread !! This it's not still true. If you have time to help us fixing
this problem I'd search some old mail to describe you the problem in


More information about the FreeTDS mailing list