📄 test_server.c
字号:
/*** State information about the server is stored in a static variable** named "g" as follows:*/static struct ServerState { pthread_mutex_t queueMutex; /* Hold this mutex to access the msg queue */ pthread_mutex_t serverMutex; /* Held by the server while it is running */ pthread_cond_t serverWakeup; /* Signal this condvar to wake up the server */ volatile int serverHalt; /* Server halts itself when true */ SqlMessage *pQueueHead; /* Head of the message queue */ SqlMessage *pQueueTail; /* Tail of the message queue */} g = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER,};/*** Send a message to the server. Block until we get a reply.**** The mutex and condition variable in the message are uninitialized** when this routine is called. This routine takes care of ** initializing them and destroying them when it has finished.*/static void sendToServer(SqlMessage *pMsg){ /* Initialize the mutex and condition variable on the message */ pthread_mutex_init(&pMsg->clientMutex, 0); pthread_cond_init(&pMsg->clientWakeup, 0); /* Add the message to the head of the server's message queue. */ pthread_mutex_lock(&g.queueMutex); pMsg->pNext = g.pQueueHead; if( g.pQueueHead==0 ){ g.pQueueTail = pMsg; }else{ g.pQueueHead->pPrev = pMsg; } pMsg->pPrev = 0; g.pQueueHead = pMsg; pthread_mutex_unlock(&g.queueMutex); /* Signal the server that the new message has be queued, then ** block waiting for the server to process the message. */ pthread_mutex_lock(&pMsg->clientMutex); pthread_cond_signal(&g.serverWakeup); while( pMsg->op!=MSG_Done ){ pthread_cond_wait(&pMsg->clientWakeup, &pMsg->clientMutex); } pthread_mutex_unlock(&pMsg->clientMutex); /* Destroy the mutex and condition variable of the message. */ pthread_mutex_destroy(&pMsg->clientMutex); pthread_cond_destroy(&pMsg->clientWakeup);}/*** The following 6 routines are client-side implementations of the** core SQLite interfaces:**** sqlite3_open** sqlite3_prepare** sqlite3_step** sqlite3_reset** sqlite3_finalize** sqlite3_close**** Clients should use the following client-side routines instead of ** the core routines above.**** sqlite3_client_open** sqlite3_client_prepare** sqlite3_client_step** sqlite3_client_reset** sqlite3_client_finalize** sqlite3_client_close**** Each of these routines creates a message for the desired operation,** sends that message to the server, waits for the server to process** then message and return a response.*/int sqlite3_client_open(const char *zDatabaseName, sqlite3 **ppDb){ SqlMessage msg; msg.op = MSG_Open; msg.zIn = zDatabaseName; sendToServer(&msg); *ppDb = msg.pDb; return msg.errCode;}int sqlite3_client_prepare( sqlite3 *pDb, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail){ SqlMessage msg; msg.op = MSG_Prepare; msg.pDb = pDb; msg.zIn = zSql; msg.nByte = nByte; sendToServer(&msg); *ppStmt = msg.pStmt; if( pzTail ) *pzTail = msg.zOut; return msg.errCode;}int sqlite3_client_step(sqlite3_stmt *pStmt){ SqlMessage msg; msg.op = MSG_Step; msg.pStmt = pStmt; sendToServer(&msg); return msg.errCode;}int sqlite3_client_reset(sqlite3_stmt *pStmt){ SqlMessage msg; msg.op = MSG_Reset; msg.pStmt = pStmt; sendToServer(&msg); return msg.errCode;}int sqlite3_client_finalize(sqlite3_stmt *pStmt){ SqlMessage msg; msg.op = MSG_Finalize; msg.pStmt = pStmt; sendToServer(&msg); return msg.errCode;}int sqlite3_client_close(sqlite3 *pDb){ SqlMessage msg; msg.op = MSG_Close; msg.pDb = pDb; sendToServer(&msg); return msg.errCode;}/*** This routine implements the server. To start the server, first** make sure g.serverHalt is false, then create a new detached thread** on this procedure. See the sqlite3_server_start() routine below** for an example. This procedure loops until g.serverHalt becomes** true.*/void *sqlite3_server(void *NotUsed){ if( pthread_mutex_trylock(&g.serverMutex) ){ return 0; /* Another server is already running */ } sqlite3_enable_shared_cache(1); while( !g.serverHalt ){ SqlMessage *pMsg; /* Remove the last message from the message queue. */ pthread_mutex_lock(&g.queueMutex); while( g.pQueueTail==0 && g.serverHalt==0 ){ pthread_cond_wait(&g.serverWakeup, &g.queueMutex); } pMsg = g.pQueueTail; if( pMsg ){ if( pMsg->pPrev ){ pMsg->pPrev->pNext = 0; }else{ g.pQueueHead = 0; } g.pQueueTail = pMsg->pPrev; } pthread_mutex_unlock(&g.queueMutex); if( pMsg==0 ) break; /* Process the message just removed */ pthread_mutex_lock(&pMsg->clientMutex); switch( pMsg->op ){ case MSG_Open: { pMsg->errCode = sqlite3_open(pMsg->zIn, &pMsg->pDb); break; } case MSG_Prepare: { pMsg->errCode = sqlite3_prepare(pMsg->pDb, pMsg->zIn, pMsg->nByte, &pMsg->pStmt, &pMsg->zOut); break; } case MSG_Step: { pMsg->errCode = sqlite3_step(pMsg->pStmt); break; } case MSG_Reset: { pMsg->errCode = sqlite3_reset(pMsg->pStmt); break; } case MSG_Finalize: { pMsg->errCode = sqlite3_finalize(pMsg->pStmt); break; } case MSG_Close: { pMsg->errCode = sqlite3_close(pMsg->pDb); break; } } /* Signal the client that the message has been processed. */ pMsg->op = MSG_Done; pthread_mutex_unlock(&pMsg->clientMutex); pthread_cond_signal(&pMsg->clientWakeup); } sqlite3_thread_cleanup(); pthread_mutex_unlock(&g.serverMutex); return 0;}/*** Start a server thread if one is not already running. If there** is aleady a server thread running, the new thread will quickly** die and this routine is effectively a no-op.*/void sqlite3_server_start(void){ pthread_t x; int rc; g.serverHalt = 0; rc = pthread_create(&x, 0, sqlite3_server, 0); if( rc==0 ){ pthread_detach(x); }}/*** If a server thread is running, then stop it. If no server is** running, this routine is effectively a no-op.**** This routine waits until the server has actually stopped before** returning.*/void sqlite3_server_stop(void){ g.serverHalt = 1; pthread_cond_broadcast(&g.serverWakeup); pthread_mutex_lock(&g.serverMutex); pthread_mutex_unlock(&g.serverMutex);}#endif /* defined(SQLITE_OS_UNIX) && OS_UNIX && SQLITE_THREADSAFE */#endif /* defined(SQLITE_SERVER) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -