Skip to content

Commit f68dd5c

Browse files
committed
Test: add a test for using a JSRuntime in a multi-thread application.
1 parent 9d6c94a commit f68dd5c

File tree

1 file changed

+155
-2
lines changed

1 file changed

+155
-2
lines changed

test/main.c

Lines changed: 155 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,14 @@
88
#include <stdio.h>
99
#include "sqlite3.h"
1010
#include "sqlitejs.h"
11+
#include <pthread.h>
1112

12-
#define DB_PATH "js_functions.sqlite"
13+
#define DB_PATH "js_functions.sqlite"
14+
15+
#define TEST_THREAD_NTHREADS 1000
16+
#define TEST_THREAD_FIRST_INIT 0
17+
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
18+
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
1319

1420
static int print_results_callback(void *data, int argc, char **argv, char **names) {
1521
for (int i = 0; i < argc; i++) {
@@ -104,6 +110,8 @@ int test_execution (void) {
104110
rc = db_exec(db, "SELECT Cos(123), cos(12.3);");
105111
rc = db_exec(db, "SELECT js_create_scalar('Sin', '(function(args){return Math.sin(args[0]);})')");
106112
rc = db_exec(db, "SELECT Sin(123), sin(12.3);");
113+
rc = db_exec(db, "SELECT js_create_scalar('f-2', '(function(args){return args[0]*10;})')");
114+
rc = db_exec(db, "SELECT [f-2](2);");
107115

108116
// aggregate
109117
printf("\nTesting js_create_aggregate\n");
@@ -170,6 +178,150 @@ int test_execution (void) {
170178
return rc;
171179
}
172180

181+
void *test_thread_init(void *ptr) {
182+
sqlite3 **ppdb = (sqlite3 **)ptr;
183+
int rc;
184+
185+
// printf("test_thread_init\n");
186+
187+
pthread_mutex_lock(&mutex);
188+
rc = sqlite3_open(":memory:", ppdb);
189+
if (rc != SQLITE_OK) goto finalize;
190+
191+
sqlite3 *db= *ppdb;
192+
193+
#if JS_LOAD_EMBEDDED
194+
rc = sqlite3_js_init(db, NULL, NULL);
195+
#else
196+
// enable load extension
197+
rc = sqlite3_enable_load_extension(db, 1);
198+
if (rc != SQLITE_OK) goto finalize;
199+
200+
rc = db_exec(db, "SELECT load_extension('./dist/js');");
201+
if (rc != SQLITE_OK) goto finalize;
202+
#endif
203+
204+
rc = db_exec(db, "SELECT js_set_max_stack_size(0)");
205+
if (rc != SQLITE_OK) goto finalize;
206+
207+
rc = db_exec(db, "SELECT js_create_scalar('x10', '(function(args){return args[0]*10;})')");
208+
if (rc != SQLITE_OK) goto finalize;
209+
210+
rc = db_exec(db, "SELECT x10(2);");
211+
if (rc != SQLITE_OK) goto finalize;
212+
213+
rc = db_exec(db, "SELECT js_eval('136*10');");
214+
if (rc != SQLITE_OK) goto finalize;
215+
216+
finalize:
217+
pthread_cond_signal(&cond); // Signal consumer
218+
pthread_mutex_unlock(&mutex);
219+
220+
// printf("test_thread_init return %d\n", rc);
221+
return (void*)(intptr_t)rc;
222+
}
223+
224+
void *test_thread_sleep(void *ptr) {
225+
sqlite3_sleep(5000);
226+
return (void*)(intptr_t)0;
227+
}
228+
229+
void *test_thread_worker(void *ptr) {
230+
sqlite3 **ppdb = (sqlite3 **)ptr;
231+
sqlite3 *db;
232+
233+
pthread_mutex_lock(&mutex);
234+
while (!(db = *ppdb)) {
235+
pthread_cond_wait(&cond, &mutex); // Wait for data
236+
}
237+
238+
// printf("test_thread_worker\n");
239+
240+
int rc = db_exec(db, "SELECT x10(2);");
241+
if (rc != SQLITE_OK) goto finalize;
242+
243+
rc = db_exec(db, "SELECT js_eval('136*10');");
244+
if (rc != SQLITE_OK) goto finalize;
245+
246+
rc = db_exec(db, "SELECT js_create_scalar('x20', '(function(args){return args[0]*20;})')");
247+
if (rc != SQLITE_OK) goto finalize;
248+
249+
rc = db_exec(db, "SELECT x20(2);");
250+
if (rc != SQLITE_OK) goto finalize;
251+
252+
finalize:
253+
pthread_mutex_unlock(&mutex);
254+
255+
// printf("test_thread_1 return %d\n", rc);
256+
return (void*)(intptr_t)rc;
257+
}
258+
259+
int test_thread (void) {
260+
sqlite3 *db = NULL;
261+
int rc;
262+
int iret;
263+
264+
// Create the a separated thread
265+
pthread_t thread1, thread_init, thread_sleep[TEST_THREAD_NTHREADS];
266+
267+
#if TEST_THREAD_FIRST_INIT
268+
iret = pthread_create(&thread_init, NULL, test_thread_init, (void*) &db);
269+
if (iret) {
270+
fprintf(stderr, "Error - pthread_create() init return code: %d\n", iret);
271+
return 1;
272+
}
273+
#endif
274+
275+
iret = pthread_create(&thread1, NULL, test_thread_worker, (void*) &db);
276+
if (iret) {
277+
fprintf(stderr, "Error - pthread_create() 1 return code: %d\n", iret);
278+
return 1;
279+
}
280+
281+
282+
for (int i=0; i<TEST_THREAD_NTHREADS; i++) {
283+
iret = pthread_create(&thread_sleep[i], NULL, test_thread_sleep, (void*) &db);
284+
if (iret) {
285+
fprintf(stderr, "Error - pthread_create() %d return code: %d\n", i, iret);
286+
return 1;
287+
}
288+
}
289+
290+
#if TEST_THREAD_FIRST_INIT == 0
291+
iret = pthread_create(&thread_init, NULL, test_thread_init, (void*) &db);
292+
if (iret) {
293+
fprintf(stderr, "Error - pthread_create() init return code: %d\n", iret);
294+
return 1;
295+
}
296+
297+
#endif
298+
299+
// Wait for the threads to complete before the main thread continues
300+
void *thread_1_rc;
301+
void *thread_init_rc;
302+
pthread_join(thread1, &thread_1_rc);
303+
pthread_join(thread_init, &thread_init_rc);
304+
rc = (int)(intptr_t)thread_1_rc;
305+
// printf("Thread 1 returns: %d\n", rc);
306+
if (rc != SQLITE_OK) goto abort_test;
307+
rc = (int)(intptr_t)thread_init_rc;
308+
// printf("Thread init returns: %d\n", rc);
309+
if (rc != SQLITE_OK) goto abort_test;
310+
311+
for (int i=0; i<TEST_THREAD_NTHREADS; i++) {
312+
void *thread_sleep_rc;
313+
pthread_join(thread_sleep[i], &thread_sleep_rc);
314+
rc = (int)(intptr_t)thread_sleep_rc;
315+
// printf("Thread %d returns: %d\n", i, rc);
316+
if (rc != SQLITE_OK) goto abort_test;
317+
}
318+
319+
abort_test:
320+
if (rc != SQLITE_OK) printf("Error: %s\n", sqlite3_errmsg(db));
321+
if (db) sqlite3_close(db);
322+
return rc;
323+
}
324+
173325
// MARK: -
174326

175327
int main (void) {
@@ -179,7 +331,8 @@ int main (void) {
179331
rc = test_serialization(DB_PATH, false, 1); // create and execute original implementations
180332
rc = test_serialization(DB_PATH, false, 2); // update functions previously registered in the js_functions table
181333
rc = test_serialization(DB_PATH, true, 3); // load the new implementations
182-
334+
rc = test_thread();
335+
183336
sqlite3_int64 current = 0;
184337
sqlite3_int64 highwater = 0;
185338
bool reset = false;

0 commit comments

Comments
 (0)