LCOV - code coverage report
Current view: top level - src/dblib/unittests - thread.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 87 111 78.4 %
Date: 2024-04-18 21:21:48 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /* 
       2             :  * Purpose: Test dblib thread safety
       3             :  */
       4             : 
       5             : #include "common.h"
       6             : #include <freetds/thread.h>
       7             : #include <freetds/utils.h>
       8             : #include <freetds/macros.h>
       9             : 
      10             : #ifdef HAVE_UNISTD_H
      11             : #include <unistd.h>
      12             : #endif
      13             : 
      14             : #include <freetds/replacements.h>
      15             : 
      16             : #ifdef TDS_HAVE_MUTEX
      17             : 
      18             : static tds_mutex mutex = TDS_MUTEX_INITIALIZER;
      19             : 
      20             : static int result = 0;
      21             : static int thread_count = 0;
      22             : 
      23             : #define ROWS 20
      24             : #define NUM_THREAD 10
      25             : #define NUM_LOOP 100
      26             : 
      27             : static void
      28             : set_failed(void)
      29             : {
      30           0 :         tds_mutex_lock(&mutex);
      31           0 :         result = 1;
      32           0 :         tds_mutex_unlock(&mutex);
      33             : }
      34             : 
      35             : static int
      36        8000 : test(DBPROCESS *dbproc)
      37             : {
      38             :         int i;
      39             :         char teststr[1024];
      40             :         DBINT testint;
      41             : 
      42             : 
      43             :         /* printf("select\n"); */
      44        8000 :         dbcmd(dbproc, "select * from dblib_thread order by i");
      45        8000 :         dbsqlexec(dbproc);
      46             : 
      47        8000 :         if (dbresults(dbproc) != SUCCEED) {
      48           0 :                 printf("Was expecting a result set.\n");
      49             :                 set_failed();
      50           0 :                 return 1;
      51             :         }
      52             : 
      53        8000 :         if (SUCCEED != dbbind(dbproc, 1, INTBIND, 0, (BYTE *) & testint)) {
      54           0 :                 fprintf(stderr, "Had problem with bind\n");
      55           0 :                 abort();
      56             :         }
      57        8000 :         if (SUCCEED != dbbind(dbproc, 2, STRINGBIND, 0, (BYTE *) teststr)) {
      58           0 :                 fprintf(stderr, "Had problem with bind\n");
      59           0 :                 abort();
      60             :         }
      61             : 
      62      160000 :         for (i = 0; i < ROWS; i++) {
      63             :                 char expected[64];
      64             : 
      65      160000 :                 sprintf(expected, "row %d", i);
      66             : 
      67      160000 :                 memset(teststr, 'x', sizeof(teststr));
      68      160000 :                 teststr[0] = 0;
      69      160000 :                 teststr[sizeof(teststr) - 1] = 0;
      70      160000 :                 if (REG_ROW != dbnextrow(dbproc)) {
      71           0 :                         fprintf(stderr, "Failed.  Expected a row\n");
      72             :                         set_failed();
      73           0 :                         return 1;
      74             :                 }
      75      160000 :                 if (testint != i) {
      76           0 :                         fprintf(stderr, "Failed.  Expected i to be %d, was %d\n", i, (int) testint);
      77           0 :                         abort();
      78             :                 }
      79      160000 :                 if (0 != strncmp(teststr, expected, strlen(expected))) {
      80           0 :                         printf("Failed.  Expected s to be |%s|, was |%s|\n", expected, teststr);
      81           0 :                         abort();
      82             :                 }
      83             :                 /* printf("Read a row of data -> %d |%s|\n", (int) testint, teststr); */
      84             :         }
      85             : 
      86             : 
      87        8000 :         if (dbnextrow(dbproc) != NO_MORE_ROWS) {
      88           0 :                 fprintf(stderr, "Was expecting no more rows\n");
      89             :                 set_failed();
      90           0 :                 return 1;
      91             :         }
      92             : 
      93        8000 :         dbcancel(dbproc);
      94             : 
      95        8000 :         return 0;
      96             : }
      97             : 
      98          80 : static TDS_THREAD_PROC_DECLARE(thread_test, arg)
      99             : {
     100             :         int i;
     101          80 :         int num = TDS_PTR2INT(arg);
     102             :         DBPROCESS *dbproc;
     103             :         LOGINREC *login;
     104             : 
     105          80 :         login = dblogin();
     106          80 :         DBSETLPWD(login, PASSWORD);
     107          80 :         DBSETLUSER(login, USER);
     108          80 :         DBSETLAPP(login, "thread");
     109             : 
     110          80 :         dbproc = dbopen(login, SERVER);
     111          80 :         if (!dbproc) {
     112           0 :                 dbloginfree(login);
     113           0 :                 fprintf(stderr, "Unable to connect to %s\n", SERVER);
     114             :                 set_failed();
     115           0 :                 return TDS_THREAD_RESULT(0);
     116             :         }
     117          80 :         dbloginfree(login);
     118             : 
     119          80 :         if (strlen(DATABASE))
     120          80 :                 dbuse(dbproc, DATABASE);
     121             : 
     122          80 :         tds_mutex_lock(&mutex);
     123          80 :         ++thread_count;
     124          80 :         tds_mutex_unlock(&mutex);
     125             : 
     126          80 :         printf("thread %2d waiting for all threads to start\n", num+1);
     127          80 :         tds_mutex_lock(&mutex);
     128        7437 :         while (thread_count < NUM_THREAD) {
     129        7277 :                 tds_mutex_unlock(&mutex);
     130        7277 :                 tds_sleep_ms(50);
     131        7277 :                 tds_mutex_lock(&mutex);
     132             :         }
     133          80 :         tds_mutex_unlock(&mutex);
     134             : 
     135        8080 :         for (i = 1; i <= NUM_LOOP; ++i) {
     136        8000 :                 printf("thread %2d of %2d loop %d\n", num+1, NUM_THREAD, i);
     137        8000 :                 if (test(dbproc) || result != 0)
     138             :                         break;
     139             :         }
     140             : 
     141          80 :         dbclose(dbproc);
     142          80 :         return TDS_THREAD_RESULT(0);
     143             : }
     144             : 
     145             : int
     146           8 : main(int argc, char **argv)
     147             : {
     148             :         int i;
     149             :         tds_thread th[NUM_THREAD];
     150             :         DBPROCESS *dbproc;
     151             :         LOGINREC *login;
     152             : 
     153           8 :         read_login_info(argc, argv);
     154             : 
     155           8 :         printf("Starting %s\n", argv[0]);
     156             : 
     157           8 :         dbinit();
     158             : 
     159           8 :         dberrhandle(syb_err_handler);
     160           8 :         dbmsghandle(syb_msg_handler);
     161             : 
     162           8 :         printf("About to logon\n");
     163             : 
     164           8 :         login = dblogin();
     165           8 :         DBSETLPWD(login, PASSWORD);
     166           8 :         DBSETLUSER(login, USER);
     167           8 :         DBSETLAPP(login, "thread");
     168             : 
     169           8 :         printf("About to open \"%s\"\n", SERVER);
     170             : 
     171           8 :         dbproc = dbopen(login, SERVER);
     172           8 :         if (!dbproc) {
     173           0 :                 fprintf(stderr, "Unable to connect to %s\n", SERVER);
     174           0 :                 return 1;
     175             :         }
     176             : 
     177           8 :         dbloginfree(login);
     178             : 
     179           8 :         if (strlen(DATABASE))
     180           8 :                 dbuse(dbproc, DATABASE);
     181             : 
     182           8 :         printf("Dropping table\n");
     183           8 :         dbcmd(dbproc, "if object_id('dblib_thread') is not null drop table dblib_thread");
     184           8 :         dbsqlexec(dbproc);
     185           8 :         while (dbresults(dbproc) == SUCCEED) {
     186             :                 /* nop */
     187             :         }
     188             : 
     189           8 :         printf("creating table\n");
     190           8 :         dbcmd(dbproc, "create table dblib_thread (i int not null, s char(10) not null)");
     191           8 :         dbsqlexec(dbproc);
     192           8 :         while (dbresults(dbproc) == SUCCEED) {
     193             :                 /* nop */
     194             :         }
     195             : 
     196           8 :         printf("insert\n");
     197         168 :         for (i = 0; i < ROWS; i++) {
     198             :                 char cmd[128];
     199             : 
     200         160 :                 sprintf(cmd, "insert into dblib_thread values (%d, 'row %d')", i, i);
     201         160 :                 dbcmd(dbproc, cmd);
     202         160 :                 dbsqlexec(dbproc);
     203         160 :                 while (dbresults(dbproc) == SUCCEED) {
     204             :                         /* nop */
     205             :                 }
     206             :         }
     207             : 
     208          80 :         for (i = 0; i < NUM_THREAD; ++i) {
     209         160 :                 int err = tds_thread_create(&th[i], thread_test, TDS_INT2PTR(i));
     210          80 :                 if (err != 0)
     211             :                 {
     212           0 :                         fprintf(stderr, "Error %d (%s) creating thread\n", err, strerror(err));
     213           0 :                         return 1;
     214             :                 }
     215             :                 /* MSSQL rejects the connections if they come in too fast */
     216          80 :                 tds_sleep_s(1);
     217             :         }
     218             : 
     219          80 :         for (i = 0; i < NUM_THREAD; ++i) {
     220         160 :                 tds_thread_join(th[i], NULL);
     221          80 :                 printf("thread: %d exited\n", i + 1);
     222             :         }
     223             : 
     224           8 :         printf("Dropping table\n");
     225           8 :         dbcmd(dbproc, "drop table dblib_thread");
     226           8 :         dbsqlexec(dbproc);
     227           8 :         while (dbresults(dbproc) == SUCCEED) {
     228             :                 /* nop */
     229             :         }
     230             : 
     231           8 :         dbexit();
     232             : 
     233           8 :         return result;
     234             : }
     235             : 
     236             : #else /* !TDS_HAVE_PTHREAD_MUTEX */
     237             : 
     238             : int
     239             : main(int argc, char **argv)
     240             : {
     241             :         printf("Not possible for this platform.\n");
     242             :         return 0;
     243             : }
     244             : #endif

Generated by: LCOV version 1.13