1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/sqlite3api/TEST/TclScript/threadtest1.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,289 @@
1.4 +/*
1.5 +** 2002 January 15
1.6 +**
1.7 +** The author disclaims copyright to this source code. In place of
1.8 +** a legal notice, here is a blessing:
1.9 +**
1.10 +** May you do good and not evil.
1.11 +** May you find forgiveness for yourself and forgive others.
1.12 +** May you share freely, never taking more than you give.
1.13 +**
1.14 +*************************************************************************
1.15 +** This file implements a simple standalone program used to test whether
1.16 +** or not the SQLite library is threadsafe.
1.17 +**
1.18 +** Testing the thread safety of SQLite is difficult because there are very
1.19 +** few places in the code that are even potentially unsafe, and those
1.20 +** places execute for very short periods of time. So even if the library
1.21 +** is compiled with its mutexes disabled, it is likely to work correctly
1.22 +** in a multi-threaded program most of the time.
1.23 +**
1.24 +** This file is NOT part of the standard SQLite library. It is used for
1.25 +** testing only.
1.26 +*/
1.27 +#include "sqlite.h"
1.28 +#include <pthread.h>
1.29 +#include <sched.h>
1.30 +#include <stdio.h>
1.31 +#include <stdlib.h>
1.32 +#include <string.h>
1.33 +#include <unistd.h>
1.34 +
1.35 +/*
1.36 +** Enable for tracing
1.37 +*/
1.38 +static int verbose = 0;
1.39 +
1.40 +/*
1.41 +** Come here to die.
1.42 +*/
1.43 +static void Exit(int rc){
1.44 + exit(rc);
1.45 +}
1.46 +
1.47 +extern char *sqlite3_mprintf(const char *zFormat, ...);
1.48 +extern char *sqlite3_vmprintf(const char *zFormat, va_list);
1.49 +
1.50 +/*
1.51 +** When a lock occurs, yield.
1.52 +*/
1.53 +static int db_is_locked(void *NotUsed, int iCount){
1.54 + /* sched_yield(); */
1.55 + if( verbose ) printf("BUSY %s #%d\n", (char*)NotUsed, iCount);
1.56 + usleep(100);
1.57 + return iCount<25;
1.58 +}
1.59 +
1.60 +/*
1.61 +** Used to accumulate query results by db_query()
1.62 +*/
1.63 +struct QueryResult {
1.64 + const char *zFile; /* Filename - used for error reporting */
1.65 + int nElem; /* Number of used entries in azElem[] */
1.66 + int nAlloc; /* Number of slots allocated for azElem[] */
1.67 + char **azElem; /* The result of the query */
1.68 +};
1.69 +
1.70 +/*
1.71 +** The callback function for db_query
1.72 +*/
1.73 +static int db_query_callback(
1.74 + void *pUser, /* Pointer to the QueryResult structure */
1.75 + int nArg, /* Number of columns in this result row */
1.76 + char **azArg, /* Text of data in all columns */
1.77 + char **NotUsed /* Names of the columns */
1.78 +){
1.79 + struct QueryResult *pResult = (struct QueryResult*)pUser;
1.80 + int i;
1.81 + if( pResult->nElem + nArg >= pResult->nAlloc ){
1.82 + if( pResult->nAlloc==0 ){
1.83 + pResult->nAlloc = nArg+1;
1.84 + }else{
1.85 + pResult->nAlloc = pResult->nAlloc*2 + nArg + 1;
1.86 + }
1.87 + pResult->azElem = realloc( pResult->azElem, pResult->nAlloc*sizeof(char*));
1.88 + if( pResult->azElem==0 ){
1.89 + fprintf(stdout,"%s: malloc failed\n", pResult->zFile);
1.90 + return 1;
1.91 + }
1.92 + }
1.93 + if( azArg==0 ) return 0;
1.94 + for(i=0; i<nArg; i++){
1.95 + pResult->azElem[pResult->nElem++] =
1.96 + sqlite3_mprintf("%s",azArg[i] ? azArg[i] : "");
1.97 + }
1.98 + return 0;
1.99 +}
1.100 +
1.101 +/*
1.102 +** Execute a query against the database. NULL values are returned
1.103 +** as an empty string. The list is terminated by a single NULL pointer.
1.104 +*/
1.105 +char **db_query(sqlite *db, const char *zFile, const char *zFormat, ...){
1.106 + char *zSql;
1.107 + int rc;
1.108 + char *zErrMsg = 0;
1.109 + va_list ap;
1.110 + struct QueryResult sResult;
1.111 + va_start(ap, zFormat);
1.112 + zSql = sqlite3_vmprintf(zFormat, ap);
1.113 + va_end(ap);
1.114 + memset(&sResult, 0, sizeof(sResult));
1.115 + sResult.zFile = zFile;
1.116 + if( verbose ) printf("QUERY %s: %s\n", zFile, zSql);
1.117 + rc = sqlite3_exec(db, zSql, db_query_callback, &sResult, &zErrMsg);
1.118 + if( rc==SQLITE_SCHEMA ){
1.119 + if( zErrMsg ) free(zErrMsg);
1.120 + rc = sqlite3_exec(db, zSql, db_query_callback, &sResult, &zErrMsg);
1.121 + }
1.122 + if( verbose ) printf("DONE %s %s\n", zFile, zSql);
1.123 + if( zErrMsg ){
1.124 + fprintf(stdout,"%s: query failed: %s - %s\n", zFile, zSql, zErrMsg);
1.125 + free(zErrMsg);
1.126 + free(zSql);
1.127 + Exit(1);
1.128 + }
1.129 + sqlite3_free(zSql);
1.130 + if( sResult.azElem==0 ){
1.131 + db_query_callback(&sResult, 0, 0, 0);
1.132 + }
1.133 + sResult.azElem[sResult.nElem] = 0;
1.134 + return sResult.azElem;
1.135 +}
1.136 +
1.137 +/*
1.138 +** Execute an SQL statement.
1.139 +*/
1.140 +void db_execute(sqlite *db, const char *zFile, const char *zFormat, ...){
1.141 + char *zSql;
1.142 + int rc;
1.143 + char *zErrMsg = 0;
1.144 + va_list ap;
1.145 + va_start(ap, zFormat);
1.146 + zSql = sqlite3_vmprintf(zFormat, ap);
1.147 + va_end(ap);
1.148 + if( verbose ) printf("EXEC %s: %s\n", zFile, zSql);
1.149 + do{
1.150 + rc = sqlite3_exec(db, zSql, 0, 0, &zErrMsg);
1.151 + }while( rc==SQLITE_BUSY );
1.152 + if( verbose ) printf("DONE %s: %s\n", zFile, zSql);
1.153 + if( zErrMsg ){
1.154 + fprintf(stdout,"%s: command failed: %s - %s\n", zFile, zSql, zErrMsg);
1.155 + free(zErrMsg);
1.156 + sqlite3_free(zSql);
1.157 + Exit(1);
1.158 + }
1.159 + sqlite3_free(zSql);
1.160 +}
1.161 +
1.162 +/*
1.163 +** Free the results of a db_query() call.
1.164 +*/
1.165 +void db_query_free(char **az){
1.166 + int i;
1.167 + for(i=0; az[i]; i++){
1.168 + sqlite3_free(az[i]);
1.169 + }
1.170 + free(az);
1.171 +}
1.172 +
1.173 +/*
1.174 +** Check results
1.175 +*/
1.176 +void db_check(const char *zFile, const char *zMsg, char **az, ...){
1.177 + va_list ap;
1.178 + int i;
1.179 + char *z;
1.180 + va_start(ap, az);
1.181 + for(i=0; (z = va_arg(ap, char*))!=0; i++){
1.182 + if( az[i]==0 || strcmp(az[i],z)!=0 ){
1.183 + fprintf(stdout,"%s: %s: bad result in column %d: %s\n",
1.184 + zFile, zMsg, i+1, az[i]);
1.185 + db_query_free(az);
1.186 + Exit(1);
1.187 + }
1.188 + }
1.189 + va_end(ap);
1.190 + db_query_free(az);
1.191 +}
1.192 +
1.193 +pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
1.194 +pthread_cond_t sig = PTHREAD_COND_INITIALIZER;
1.195 +int thread_cnt = 0;
1.196 +
1.197 +static void *worker_bee(void *pArg){
1.198 + const char *zFilename = (char*)pArg;
1.199 + char *azErr;
1.200 + int i, cnt;
1.201 + int t = atoi(zFilename);
1.202 + char **az;
1.203 + sqlite *db;
1.204 +
1.205 + pthread_mutex_lock(&lock);
1.206 + thread_cnt++;
1.207 + pthread_mutex_unlock(&lock);
1.208 + printf("%s: START\n", zFilename);
1.209 + fflush(stdout);
1.210 + for(cnt=0; cnt<10; cnt++){
1.211 + sqlite3_open(&zFilename[2], &db);
1.212 + if( db==0 ){
1.213 + fprintf(stdout,"%s: can't open\n", zFilename);
1.214 + Exit(1);
1.215 + }
1.216 + sqlite3_busy_handler(db, db_is_locked, zFilename);
1.217 + db_execute(db, zFilename, "CREATE TABLE t%d(a,b,c);", t);
1.218 + for(i=1; i<=100; i++){
1.219 + db_execute(db, zFilename, "INSERT INTO t%d VALUES(%d,%d,%d);",
1.220 + t, i, i*2, i*i);
1.221 + }
1.222 + az = db_query(db, zFilename, "SELECT count(*) FROM t%d", t);
1.223 + db_check(zFilename, "tX size", az, "100", 0);
1.224 + az = db_query(db, zFilename, "SELECT avg(b) FROM t%d", t);
1.225 + db_check(zFilename, "tX avg", az, "101", 0);
1.226 + db_execute(db, zFilename, "DELETE FROM t%d WHERE a>50", t);
1.227 + az = db_query(db, zFilename, "SELECT avg(b) FROM t%d", t);
1.228 + db_check(zFilename, "tX avg2", az, "51", 0);
1.229 + for(i=1; i<=50; i++){
1.230 + char z1[30], z2[30];
1.231 + az = db_query(db, zFilename, "SELECT b, c FROM t%d WHERE a=%d", t, i);
1.232 + sprintf(z1, "%d", i*2);
1.233 + sprintf(z2, "%d", i*i);
1.234 + db_check(zFilename, "readback", az, z1, z2, 0);
1.235 + }
1.236 + db_execute(db, zFilename, "DROP TABLE t%d;", t);
1.237 + sqlite3_close(db);
1.238 + }
1.239 + printf("%s: END\n", zFilename);
1.240 + /* unlink(zFilename); */
1.241 + fflush(stdout);
1.242 + pthread_mutex_lock(&lock);
1.243 + thread_cnt--;
1.244 + if( thread_cnt<=0 ){
1.245 + pthread_cond_signal(&sig);
1.246 + }
1.247 + pthread_mutex_unlock(&lock);
1.248 + return 0;
1.249 +}
1.250 +
1.251 +int main(int argc, char **argv){
1.252 + char *zFile;
1.253 + int i, n;
1.254 + pthread_t id;
1.255 + if( argc>2 && strcmp(argv[1], "-v")==0 ){
1.256 + verbose = 1;
1.257 + argc--;
1.258 + argv++;
1.259 + }
1.260 + if( argc<2 || (n=atoi(argv[1]))<1 ) n = 10;
1.261 + for(i=0; i<n; i++){
1.262 + char zBuf[200];
1.263 + sprintf(zBuf, "testdb-%d", (i+1)/2);
1.264 + unlink(zBuf);
1.265 + }
1.266 + for(i=0; i<n; i++){
1.267 + zFile = sqlite3_mprintf("%d.testdb-%d", i%2+1, (i+2)/2);
1.268 + if( (i%2)==0 ){
1.269 + /* Remove both the database file and any old journal for the file
1.270 + ** being used by this thread and the next one. */
1.271 + char *zDb = &zFile[2];
1.272 + char *zJournal = sqlite3_mprintf("%s-journal", zDb);
1.273 + unlink(zDb);
1.274 + unlink(zJournal);
1.275 + free(zJournal);
1.276 + }
1.277 +
1.278 + pthread_create(&id, 0, worker_bee, (void*)zFile);
1.279 + pthread_detach(id);
1.280 + }
1.281 + pthread_mutex_lock(&lock);
1.282 + while( thread_cnt>0 ){
1.283 + pthread_cond_wait(&sig, &lock);
1.284 + }
1.285 + pthread_mutex_unlock(&lock);
1.286 + for(i=0; i<n; i++){
1.287 + char zBuf[200];
1.288 + sprintf(zBuf, "testdb-%d", (i+1)/2);
1.289 + unlink(zBuf);
1.290 + }
1.291 + return 0;
1.292 +}