Skip to Content.
Sympa Menu

freetds - Re: [freetds] dblib and thread safety

freetds AT lists.ibiblio.org

Subject: FreeTDS Development Group

List archive

Chronological Thread  
  • From: liam AT inodes.org
  • To: FreeTDS Development Group <freetds AT lists.ibiblio.org>
  • Subject: Re: [freetds] dblib and thread safety
  • Date: Thu, 16 Sep 2004 13:05:25 +1000

On Tue, Sep 14, 2004 at 04:05:38PM +0200, ZIGLIO, Frediano, VF-IT wrote:

> I think you are right. Do you know a small and portable library to do
> this job (using mutex) ??

Well, for POSIX hosts, POSIX 1003.1c threads is the right answer. For Win32,
another set of ifdefs that add critical sections would be fine. However,
as I'm not a Win32 person, I can't code/test this.

Please find attached my patch to the latest CVS snapshot for dblib.c.
I've done some functional and load tests on Solaris and Linux and so
far, so good.

Appreciate it if you could apply it to CVS.

Cheers,
Liam
--- ../../../freetds-0.63.dev.20040824/src/dblib/dblib.c 2004-07-29
20:22:40.000000000 +1000
+++ dblib.c 2004-09-16 12:57:45.000000000 +1000
@@ -21,6 +21,10 @@
#include <config.h>
#endif /* HAVE_CONFIG_H */

+#ifdef _THREAD_SAFE
+#include <pthread.h>
+#endif
+
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
@@ -109,9 +113,27 @@
int connection_list_size_represented;
char *recftos_filename;
int recftos_filenum;
+#ifdef _THREAD_SAFE
+ pthread_mutex_t mutex;
+#endif
}
DBLIBCONTEXT;

+typedef struct dblib_timeout_context {
+ int g_dblib_login_timeout; /* not used unless > -1 */
+ int g_dblib_query_timeout; /* not used unless > -1 */
+#ifdef _THREAD_SAFE
+ pthread_mutex_t mutex;
+#endif
+}
+DBLIBTIMEOUTCONTEXT;
+
+#ifdef _THREAD_SAFE
+static DBLIBTIMEOUTCONTEXT g_dblib_timeout_ctx = { -1, -1,
PTHREAD_MUTEX_INITIALIZER };
+#else
+static DBLIBTIMEOUTCONTEXT g_dblib_timeout_ctx = { -1, -1 };
+#endif
+
static DBLIBCONTEXT g_dblib_ctx;

static int g_dblib_version =
@@ -131,8 +153,6 @@
DBVERSION_80;
#endif

-static int g_dblib_login_timeout = -1; /* not used unless positive */
-static int g_dblib_query_timeout = -1; /* not used unless positive */

static int
dblib_add_connection(DBLIBCONTEXT * ctx, TDSSOCKET * tds)
@@ -516,15 +536,27 @@
RETCODE
dbinit(void)
{
+#ifdef _THREAD_SAFE
+ pthread_mutexattr_t attr;
+#endif
/*
* DBLIBCONTEXT stores a list of current connections so they may be
closed
* with dbexit()
*/
memset(&g_dblib_ctx, '\0', sizeof(DBLIBCONTEXT));
+#ifdef _THREAD_SAFE
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&g_dblib_ctx.mutex, &attr);
+ pthread_mutex_lock(&g_dblib_ctx.mutex);
+#endif

g_dblib_ctx.connection_list = (TDSSOCKET **) calloc(TDS_MAX_CONN,
sizeof(TDSSOCKET *));
if (g_dblib_ctx.connection_list == NULL) {
tdsdump_log(TDS_DBG_FUNC, "dbinit: out of memory\n");
+#ifdef _THREAD_SAFE
+ pthread_mutex_unlock(&g_dblib_ctx.mutex);
+#endif
return FAIL;
}
g_dblib_ctx.connection_list_size = TDS_MAX_CONN;
@@ -547,6 +579,10 @@
g_dblib_ctx.tds_ctx->locale->date_fmt = strdup("%b %e %Y
%I:%M:%S:%z%p");
}

+#ifdef _THREAD_SAFE
+ pthread_mutex_unlock(&g_dblib_ctx.mutex);
+#endif
+
return SUCCEED;
}

@@ -948,6 +984,10 @@

tds_set_server(login->tds_login, server);

+#ifdef _THREAD_SAFE
+ pthread_mutex_lock(&g_dblib_ctx.mutex);
+#endif
+
dbproc->tds_socket = tds_alloc_socket(g_dblib_ctx.tds_ctx, 512);
tds_set_parent(dbproc->tds_socket, (void *) dbproc);
dbproc->tds_socket->option_flag2 &= ~0x02; /* we're not an ODBC
driver */
@@ -957,18 +997,27 @@
dbproc->servcharset[0] = '\0';

connection = tds_read_config_info(NULL, login->tds_login,
g_dblib_ctx.tds_ctx->locale);
- if (!connection)
+ if (!connection) {
+#ifdef _THREAD_SAFE
+ pthread_mutex_unlock(&g_dblib_ctx.mutex);
+#endif
return NULL;
-
+ }
/* override connection timeout if dbsetlogintime() was called */
- if (g_dblib_login_timeout >= 0) {
- connection->connect_timeout = g_dblib_login_timeout;
+#ifdef _THREAD_SAFE
+ pthread_mutex_lock(&g_dblib_timeout_ctx.mutex);
+#endif
+ if (g_dblib_timeout_ctx.g_dblib_login_timeout >= 0) {
+ connection->connect_timeout =
g_dblib_timeout_ctx.g_dblib_login_timeout;
}

/* override query timeout if dbsettime() was called */
- if (g_dblib_query_timeout >= 0) {
- connection->timeout = g_dblib_query_timeout;
+ if (g_dblib_timeout_ctx.g_dblib_query_timeout >= 0) {
+ connection->timeout =
g_dblib_timeout_ctx.g_dblib_query_timeout;
}
+#ifdef _THREAD_SAFE
+ pthread_mutex_unlock(&g_dblib_timeout_ctx.mutex);
+#endif

dbproc->dbchkintr = NULL;
dbproc->dbhndlintr = NULL;
@@ -978,6 +1027,9 @@
if (tds_connect(dbproc->tds_socket, connection) == TDS_FAIL) {
dbproc->tds_socket = NULL;
tds_free_connection(connection);
+#ifdef _THREAD_SAFE
+ pthread_mutex_unlock(&g_dblib_ctx.mutex);
+#endif
return NULL;
}
tds_free_connection(connection);
@@ -990,6 +1042,9 @@
} else {
fprintf(stderr, "DB-Library: Login incorrect.\n");
free(dbproc); /* memory leak fix (mlilback, 11/17/01) */
+#ifdef _THREAD_SAFE
+ pthread_mutex_unlock(&g_dblib_ctx.mutex);
+#endif
return NULL;
}

@@ -1010,6 +1065,9 @@
g_dblib_ctx.recftos_filenum++;
}
}
+#ifdef _THREAD_SAFE
+ pthread_mutex_unlock(&g_dblib_ctx.mutex);
+#endif
return dbproc;
}

@@ -1227,7 +1285,13 @@
dbstring_free(&(dbproc->dboptcmd));

dbfreebuf(dbproc);
+#ifdef _THREAD_SAFE
+ pthread_mutex_lock(&g_dblib_ctx.mutex);
+#endif
dblib_del_connection(&g_dblib_ctx, dbproc->tds_socket);
+#ifdef _THREAD_SAFE
+ pthread_mutex_unlock(&g_dblib_ctx.mutex);
+#endif
free(dbproc);

return;
@@ -1246,8 +1310,12 @@
TDSSOCKET *tds;
DBPROCESS *dbproc;
int i;
- const int list_size = g_dblib_ctx.connection_list_size;
+ int list_size;

+#ifdef _THREAD_SAFE
+ pthread_mutex_lock(&g_dblib_ctx.mutex);
+#endif
+ list_size = g_dblib_ctx.connection_list_size;

/* FIX ME -- this breaks if ctlib/dblib used in same process */
for (i = 0; i < list_size; i++) {
@@ -1267,6 +1335,9 @@
tds_free_context(g_dblib_ctx.tds_ctx);
g_dblib_ctx.tds_ctx = NULL;
}
+#ifdef _THREAD_SAFE
+ pthread_mutex_unlock(&g_dblib_ctx.mutex);
+#endif
}

/** \internal
@@ -1819,7 +1890,13 @@

tdsdump_log(TDS_DBG_INFO1, "dbconvert() calling tds_convert\n");

+#ifdef _THREAD_SAFE
+ pthread_mutex_lock(&g_dblib_ctx.mutex);
+#endif
len = tds_convert(g_dblib_ctx.tds_ctx, srctype, (const TDS_CHAR *)
src, srclen, desttype, &dres);
+#ifdef _THREAD_SAFE
+ pthread_mutex_unlock(&g_dblib_ctx.mutex);
+#endif
tdsdump_log(TDS_DBG_INFO1, "dbconvert() called tds_convert returned
%d\n", len);

switch (len) {
@@ -3230,7 +3307,13 @@
dbsetmaxprocs(int maxprocs)
{
int i;
- TDSSOCKET **old_list = g_dblib_ctx.connection_list;
+ TDSSOCKET **old_list = NULL;
+
+#ifdef _THREAD_SAFE
+ pthread_mutex_lock(&g_dblib_ctx.mutex);
+#endif
+
+ old_list = g_dblib_ctx.connection_list;

tdsdump_log(TDS_DBG_FUNC, "UNTESTED dbsetmaxprocs()\n");
/*
@@ -3241,6 +3324,9 @@
*/
if (maxprocs < g_dblib_ctx.connection_list_size) {
g_dblib_ctx.connection_list_size_represented = maxprocs;
+#ifdef _THREAD_SAFE
+ pthread_mutex_unlock(&g_dblib_ctx.mutex);
+#endif
return SUCCEED;
}

@@ -3248,6 +3334,10 @@

if (g_dblib_ctx.connection_list == NULL) {
g_dblib_ctx.connection_list = old_list;
+
+#ifdef _THREAD_SAFE
+ pthread_mutex_unlock(&g_dblib_ctx.mutex);
+#endif
return FAIL;
}

@@ -3258,6 +3348,10 @@
g_dblib_ctx.connection_list_size = maxprocs;
g_dblib_ctx.connection_list_size_represented = maxprocs;

+#ifdef _THREAD_SAFE
+ pthread_mutex_unlock(&g_dblib_ctx.mutex);
+#endif
+
return SUCCEED;
}

@@ -3271,7 +3365,15 @@
int
dbgetmaxprocs(void)
{
- return g_dblib_ctx.connection_list_size_represented;
+ int c;
+#ifdef _THREAD_SAFE
+ pthread_mutex_lock(&g_dblib_ctx.mutex);
+#endif
+ c = g_dblib_ctx.connection_list_size_represented;
+#ifdef _THREAD_SAFE
+ pthread_mutex_unlock(&g_dblib_ctx.mutex);
+#endif
+ return c;
}

/**
@@ -3287,7 +3389,13 @@
dbsettime(int seconds)
{
tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED dbsettime()\n");
- g_dblib_query_timeout = seconds;
+#ifdef _THREAD_SAFE
+ pthread_mutex_lock(&g_dblib_timeout_ctx.mutex);
+#endif
+ g_dblib_timeout_ctx.g_dblib_query_timeout = seconds;
+#ifdef _THREAD_SAFE
+ pthread_mutex_unlock(&g_dblib_timeout_ctx.mutex);
+#endif
return SUCCEED;
}

@@ -3302,7 +3410,13 @@
RETCODE
dbsetlogintime(int seconds)
{
- g_dblib_login_timeout = seconds;
+#ifdef _THREAD_SAFE
+ pthread_mutex_lock(&g_dblib_timeout_ctx.mutex);
+#endif
+ g_dblib_timeout_ctx.g_dblib_login_timeout = seconds;
+#ifdef _THREAD_SAFE
+ pthread_mutex_unlock(&g_dblib_timeout_ctx.mutex);
+#endif
return SUCCEED;
}

@@ -5473,11 +5587,17 @@
void
dbrecftos(char *filename)
{
+#ifdef _THREAD_SAFE
+ pthread_mutex_lock(&g_dblib_ctx.mutex);
+#endif
g_dblib_ctx.recftos_filename = malloc(strlen(filename) + 1);
if (g_dblib_ctx.recftos_filename != (char *) NULL) {
strcpy(g_dblib_ctx.recftos_filename, filename);
g_dblib_ctx.recftos_filenum = 0;
}
+#ifdef _THREAD_SAFE
+ pthread_mutex_unlock(&g_dblib_ctx.mutex);
+#endif
}

/** \internal
@@ -6047,10 +6167,18 @@
_dblib_client_msg(DBPROCESS * dbproc, int dberr, int severity, const char
*dberrstr)
{
TDSSOCKET *tds = NULL;
+ int r;

if (dbproc)
tds = dbproc->tds_socket;
- return tds_client_msg(g_dblib_ctx.tds_ctx, tds, dberr, severity, -1,
-1, dberrstr);
+#ifdef _THREAD_SAFE
+ pthread_mutex_lock(&g_dblib_ctx.mutex);
+#endif
+ r = tds_client_msg(g_dblib_ctx.tds_ctx, tds, dberr, severity, -1, -1,
dberrstr);
+#ifdef _THREAD_SAFE
+ pthread_mutex_unlock(&g_dblib_ctx.mutex);
+#endif
+ return r;
}

static char *
@@ -6273,7 +6401,13 @@
dres.n.scale = num->scale;
}

+#ifdef _THREAD_SAFE
+ pthread_mutex_lock(&g_dblib_ctx.mutex);
+#endif
len = tds_convert(g_dblib_ctx.tds_ctx, srctype, (const TDS_CHAR *)
src, srclen, desttype, &dres);
+#ifdef _THREAD_SAFE
+ pthread_mutex_unlock(&g_dblib_ctx.mutex);
+#endif
tdsdump_log(TDS_DBG_INFO1, "copy_data_to_host_var() called
tds_convert returned %d\n", len);

switch (len) {



Archive powered by MHonArc 2.6.24.

Top of Page