/* multi-threaded C program that shouldn't leak memory. testing for Memory leak using SELECT statements in a multi-threaded application. gcc bug62849.c -o bug62849 -g `mysql_config --include` `mysql_config --libs_r` */ #include #include #define TESTTIME (259200) #define NUMTHREADS (5) char host[]="127.0.0.1"; int port=3306; char username[]="root"; char password[]=""; char database[]="callsystem"; #include #include #include #include #include pid_t PID; unsigned long MEM_START, MEM_NOW, MEM_LAST; pthread_t pthreads[NUMTHREADS]; unsigned long client_version=0; unsigned long server_version=0; unsigned long num_queries=0; int threaddone=0; int db_query(MYSQL *dbc,char *sql,int showresults); char* alocmem(size_t num); // Get memory usage. unsigned long getmem (int PID) { struct proc_t { int pid; // process id char cmd[16]; // basename of executable file in call to exec(2) char state; // single-char code for process state (S=sleeping) int ppid; // pid of parent process int pgrp; // process group id int session; // session id int tty; // full device number of controlling terminal int tpgid; // terminal process group id unsigned long flags; // kernel flags for the process unsigned long min_flt; // number of minor page faults since process start unsigned long cmin_flt; // cumulative min_flt of process and child processes unsigned long maj_flt; // number of major page faults since process start unsigned long cmaj_flt; // cumulative maj_flt of process and child processes unsigned long utime; // user-mode CPU time accumulated by process unsigned long stime; // kernel-mode CPU time accumulated by process long cutime; // cumulative utime of process and reaped children long cstime; // cumulative stime of process and reaped children long priority; // kernel scheduling priority long nice; // standard unix nice level of process long timeout; // ? long it_real_value; // ? unsigned long start_time; // start time of process -- seconds since 1-1-70 unsigned long vsize; // number of pages of virtual memory ... long rss; // resident set size from /proc/#/stat unsigned long rss_rlim; // resident set size ... ? unsigned long start_code; // address of beginning of code segment unsigned long end_code; // address of end of code segment unsigned long start_stack; // address of the bottom of stack for the process unsigned long kstk_esp; // kernel stack pointer unsigned long kstk_eip; // kernel stack pointer unsigned long wchan; // address of kernel wait channel proc is sleeping in unsigned long nswap; // ? unsigned long cnswap; // cumulative nswap ? int lproc; // last processor }; FILE *memF; char L [500]; char pidFN [500]; struct proc_t P; sprintf (pidFN, "/proc/%i/stat", PID); memF = fopen (pidFN, "r"); if (memF != NULL) { if (fgets (L, sizeof (L), memF) != NULL) { char* tmp = strrchr (L, ')'); // split into "PID (cmd" and "" *tmp = '\0'; // replace trailing ')' with NUL // Parse these two strings separately, skipping the leading "(". memset (P.cmd, 0, sizeof (P.cmd)); // clear even though *P xcalloc'd ?! sscanf (L, "%d (%15c", &P.pid, P.cmd); // comm[16] in kernel sscanf (tmp+2, "%c " "%d %d %d %d %d " "%lu %lu %lu %lu %lu %lu %lu " "%ld %ld %ld %ld %ld %ld " "%lu %lu " "%ld " "%lu %lu %lu %lu %lu %lu " "%*s %*s %*s %*s " "%lu %lu %lu %*d %d", &P.state, &P.ppid, &P.pgrp, &P.session, &P.tty, &P.tpgid, &P.flags, &P.min_flt, &P.cmin_flt, &P.maj_flt, &P.cmaj_flt, &P.utime, &P.stime, &P.cutime, &P.cstime, &P.priority, &P.nice, &P.timeout, &P.it_real_value, &P.start_time, &P.vsize, &P.rss, &P.rss_rlim, &P.start_code, &P.end_code, &P.start_stack, &P.kstk_esp, &P.kstk_eip, &P.wchan, &P.nswap, &P.cnswap, &P.lproc); } fclose (memF); } return P.vsize; } void *worker_thread(void *arg) { MYSQL *dbc=NULL; my_bool auto_reconnect=1; int cancelstate=0; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,&cancelstate); dbc = mysql_init(NULL); if(NULL == dbc) { printf("mysql_init failed\n"); goto threadexit; } else { if(0!=mysql_options(dbc,MYSQL_OPT_RECONNECT,(char*)&auto_reconnect)) { printf("mysql_options() failed to set MYSQL_OPT_RECONNECT"); } if (!mysql_real_connect(dbc,host,username,password,database,port, NULL, CLIENT_FOUND_ROWS|CLIENT_MULTI_STATEMENTS|CLIENT_MULTI_RESULTS)) { printf("mysql_real_connect failed: %s (%d) (%s)", mysql_error(dbc),mysql_errno(dbc),mysql_sqlstate(dbc)); mysql_close(dbc); dbc=NULL; } } unsigned int counter=0; unsigned int repcount=0; char shortquery[1024]; memset(shortquery,0,1024); char *longquery; longquery=NULL; char *c; c=NULL; while(0==threaddone && NULL!=dbc) { c=shortquery; c+=sprintf(c,"%s"," SELECT IServer,Unit,Script,Node,Type,OnKey1,OnKey2,OnKey3,OnKey4,OnKey5,OnKey6,OnKey7,OnKey8,OnKey9,OnKey0,OnKeyP,OnKeyA,ClearKeys,WaitMess,Digits,TimeOut,OnTimeOut,Tel,Message,Function FROM callsystem.scripts WHERE ((IServer=0 AND Unit=0 AND Script='HIJGEN') OR (IServer=1 AND Unit=0 AND Script='')) AND Node='2002' ORDER BY IServer, Script, Node LIMIT 1;"); db_query(dbc,shortquery,1); } threadexit: mysql_close(dbc); mysql_thread_end(); pthread_exit(0); } int main(int argc, const char *argv[]) { MYSQL *dbc=NULL; int i=0,err=0; PID = getpid (); MEM_NOW=getmem (PID); MEM_LAST=MEM_NOW; MEM_START=MEM_NOW; printf("PID :%d, MEM:%d\n", PID, getmem (PID)); srand48((unsigned long)1348490240); time_t timestart=0,timenow=0; unsigned int counter=0; counter=0; char shortquery[1024]={0}; char *longquery=NULL; longquery=NULL; char *c=NULL; my_init(); if (!(dbc = mysql_init(NULL))) { printf("mysql_init failed\n"); dbc=NULL; goto threadexit; } else { if (!mysql_real_connect(dbc,host,username,password,database,port, NULL, CLIENT_FOUND_ROWS|CLIENT_MULTI_STATEMENTS|CLIENT_MULTI_RESULTS)) { printf("mysql_real_connect failed: %s (%d) (%s)", mysql_error(dbc),mysql_errno(dbc),mysql_sqlstate(dbc)); mysql_close(dbc); dbc=NULL; goto threadexit; } } printf("running initializations..\n"); client_version=mysql_get_client_version(); server_version=mysql_get_server_version(dbc); printf("client version=%lu\n",client_version); printf("server version=%lu\n",server_version); if((client_version/10000) < (server_version/10000)) { printf("different client and server version! please upgrade client library!\n"); //goto threadexit; } if (!mysql_thread_safe()) { printf("non-threadsafe client detected! please rebuild and link with libmysql_r!\n"); } mysql_close(dbc); printf("about to spawn %d threads\n",NUMTHREADS); for (i=0;i 0) { myerrno=mysql_errno(dbc); printf("query failed '%s' : %d (%s) (%s)\n",sql,myerrno,mysql_error(dbc),mysql_sqlstate(dbc)); return 0; } num_queries++; do { r = mysql_use_result(dbc); if(r) { unsigned int numfields = mysql_num_fields(r); //unsigned int numrows=mysql_num_rows(r); while(0!=(field = mysql_fetch_field(r))) { //print metadata information about each field if(showresults > 1) { printf("%s ",field->name); } } if(showresults > 1) { printf("\n------------------------------------\n"); } while (0!=(w = mysql_fetch_row(r))) { for(i = 0; i < numfields; i++) { //print each field here if(showresults > 1) { printf("%s\t",w[i]); } } if(showresults > 1) { printf("\n"); } } if(showresults > 1) { printf("\n"); } mysql_free_result(r); } else //no rows returned. was it a select? { if(mysql_field_count(dbc) > 0 && showresults > 0) { printf("No results for '%s'. (%d) - %s (%s)\n",sql,mysql_errno(dbc),mysql_error(dbc),mysql_sqlstate(dbc)); return 0; } else //it could have been some insert/update/delete { //this is successful query } } moreresult=mysql_next_result(dbc); if(moreresult > 0 && showresults > 0) { printf("mysql_next_result returned %d, mysql error %s, (%d) (%s)\n",moreresult,mysql_error(dbc),mysql_errno(dbc),mysql_sqlstate(dbc)); return 0; } } while (0==moreresult); return 1; }