2019-12-11 02:37:18 +03:00
|
|
|
/*
|
|
|
|
* Multi-thread Test for libtcc
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef FIB
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "libtcc.h"
|
|
|
|
|
|
|
|
#define M 20 /* number of states */
|
|
|
|
#define F(n) (n % 20 + 2) /* fib argument */
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
#include <windows.h>
|
|
|
|
#define TF_TYPE(func, param) DWORD WINAPI func(void *param)
|
|
|
|
typedef TF_TYPE(ThreadFunc, x);
|
|
|
|
HANDLE hh[M];
|
|
|
|
void create_thread(ThreadFunc f, int n)
|
|
|
|
{
|
|
|
|
DWORD tid;
|
|
|
|
hh[n] = CreateThread(NULL, 0, f, (void*)(size_t)n, 0, &tid);
|
|
|
|
}
|
|
|
|
void wait_threads(int n)
|
|
|
|
{
|
|
|
|
WaitForMultipleObjects(n, hh, TRUE, INFINITE);
|
|
|
|
while (n)
|
|
|
|
CloseHandle(hh[--n]);
|
|
|
|
}
|
|
|
|
void sleep_ms(unsigned n)
|
|
|
|
{
|
|
|
|
Sleep(n);
|
|
|
|
}
|
|
|
|
#else
|
2019-12-12 05:31:21 +03:00
|
|
|
#include <sys/time.h>
|
|
|
|
#include <unistd.h>
|
2019-12-11 02:37:18 +03:00
|
|
|
#include <pthread.h>
|
|
|
|
#define TF_TYPE(func, param) void* func(void *param)
|
|
|
|
typedef TF_TYPE(ThreadFunc, x);
|
|
|
|
pthread_t hh[M];
|
|
|
|
void create_thread(ThreadFunc f, int n)
|
|
|
|
{
|
|
|
|
pthread_create(&hh[n], NULL, f, (void*)(size_t)n);
|
|
|
|
}
|
|
|
|
void wait_threads(int n)
|
|
|
|
{
|
|
|
|
while (n)
|
|
|
|
pthread_join(hh[--n], NULL);
|
|
|
|
|
|
|
|
}
|
|
|
|
void sleep_ms(unsigned n)
|
|
|
|
{
|
|
|
|
usleep(n * 1000);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void handle_error(void *opaque, const char *msg)
|
|
|
|
{
|
|
|
|
fprintf(opaque, "%s\n", msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* this function is called by the generated code */
|
|
|
|
int add(int a, int b)
|
|
|
|
{
|
|
|
|
return a + b;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define _str(s) #s
|
|
|
|
#define str(s) _str(s)
|
|
|
|
/* as a trick, prepend #line directive for better error/warning messages */
|
|
|
|
#define PROG(lbl) \
|
|
|
|
char lbl[] = "#line " str(__LINE__) " " str(__FILE__) "\n\n"
|
|
|
|
|
|
|
|
PROG(my_program)
|
|
|
|
"#include <tcclib.h>\n" /* include the "Simple libc header for TCC" */
|
|
|
|
"int add(int a, int b);\n"
|
|
|
|
"int fib(int n)\n"
|
|
|
|
"{\n"
|
|
|
|
" if (n <= 2)\n"
|
|
|
|
" return 1;\n"
|
|
|
|
" else\n"
|
|
|
|
" return add(fib(n-1),fib(n-2));\n"
|
|
|
|
"}\n"
|
|
|
|
"\n"
|
|
|
|
"int foo(int n)\n"
|
|
|
|
"{\n"
|
|
|
|
" printf(\" %d\", fib(n));\n"
|
|
|
|
" return 0;\n"
|
|
|
|
"# warning is this the correct file:line...\n"
|
|
|
|
"}\n";
|
|
|
|
|
|
|
|
int g_argc; char **g_argv;
|
|
|
|
|
|
|
|
void parse_args(TCCState *s)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
/* if tcclib.h and libtcc1.a are not installed, where can we find them */
|
|
|
|
for (i = 1; i < g_argc; ++i) {
|
|
|
|
char *a = g_argv[i];
|
|
|
|
if (a[0] == '-') {
|
|
|
|
if (a[1] == 'B')
|
|
|
|
tcc_set_lib_path(s, a+2);
|
|
|
|
else if (a[1] == 'I')
|
|
|
|
tcc_add_include_path(s, a+2);
|
|
|
|
else if (a[1] == 'L')
|
|
|
|
tcc_add_library_path(s, a+2);
|
2019-12-11 19:57:43 +03:00
|
|
|
else if (a[1] == 'D') {
|
2019-12-15 01:58:45 +03:00
|
|
|
char *dup = strdup(a);
|
|
|
|
char *eq = strchr(dup+2, '=');
|
2019-12-11 19:57:43 +03:00
|
|
|
if (eq) {
|
|
|
|
*eq = 0;
|
2019-12-15 01:58:45 +03:00
|
|
|
tcc_define_symbol(s, dup+2, eq+1);
|
2019-12-11 19:57:43 +03:00
|
|
|
*eq = '=';
|
2019-12-12 03:39:58 +03:00
|
|
|
} else
|
2019-12-15 01:58:45 +03:00
|
|
|
tcc_define_symbol(s, dup+2, NULL);
|
|
|
|
free(dup);
|
2019-12-11 19:57:43 +03:00
|
|
|
}
|
2019-12-11 02:37:18 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TCCState *new_state(int w)
|
|
|
|
{
|
|
|
|
TCCState *s = tcc_new();
|
|
|
|
if (!s) {
|
|
|
|
fprintf(stderr, __FILE__ ": could not create tcc state\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
tcc_set_error_func(s, stdout, handle_error);
|
|
|
|
parse_args(s);
|
|
|
|
if (!w) tcc_set_options(s, "-w");
|
|
|
|
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *reloc_state(TCCState *s, const char *entry)
|
|
|
|
{
|
|
|
|
void *func;
|
|
|
|
tcc_add_symbol(s, "add", add);
|
|
|
|
if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0) {
|
|
|
|
fprintf(stderr, __FILE__ ": could not relocate tcc state.\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
func = tcc_get_symbol(s, entry);
|
|
|
|
if (!func)
|
|
|
|
fprintf(stderr, __FILE__ ": could not get entry symbol.\n");
|
|
|
|
return func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* work with several states at the same time */
|
|
|
|
int state_test(void)
|
|
|
|
{
|
|
|
|
TCCState *s[M];
|
|
|
|
int (*func[M])(int);
|
|
|
|
int n;
|
|
|
|
|
|
|
|
for (n = 0; n < M + 4; ++n) {
|
|
|
|
unsigned a = n, b = n - 1, c = n - 2, d = n - 3, e = n - 4;
|
|
|
|
if (a < M)
|
|
|
|
s[a] = new_state(0);
|
|
|
|
if (b < M)
|
|
|
|
if (tcc_compile_string(s[b], my_program) == -1)
|
|
|
|
break;
|
|
|
|
if (c < M)
|
|
|
|
func[c] = reloc_state(s[c], "foo");
|
|
|
|
if (d < M && func[d])
|
|
|
|
func[d](F(d));
|
|
|
|
if (e < M)
|
|
|
|
tcc_delete(s[e]);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* simple compilation in threads */
|
|
|
|
TF_TYPE(thread_test_simple, vn)
|
|
|
|
{
|
|
|
|
TCCState *s;
|
|
|
|
int (*func)(int);
|
|
|
|
int ret;
|
|
|
|
int n = (size_t)vn;
|
|
|
|
|
|
|
|
s = new_state(0);
|
|
|
|
sleep_ms(1);
|
|
|
|
ret = tcc_compile_string(s, my_program);
|
|
|
|
sleep_ms(1);
|
|
|
|
if (ret >= 0) {
|
|
|
|
func = reloc_state(s, "foo");
|
|
|
|
if (func)
|
|
|
|
func(F(n));
|
|
|
|
}
|
|
|
|
tcc_delete(s);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* more complex compilation in threads */
|
|
|
|
TF_TYPE(thread_test_complex, vn)
|
|
|
|
{
|
|
|
|
TCCState *s;
|
|
|
|
int ret;
|
|
|
|
int n = (size_t)vn;
|
|
|
|
char *argv[30], b[10];
|
|
|
|
int argc = 0, i;
|
|
|
|
|
|
|
|
sprintf(b, "%d", F(n));
|
|
|
|
|
|
|
|
for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i];
|
|
|
|
#if 0
|
|
|
|
argv[argc++] = "-run";
|
|
|
|
for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i];
|
|
|
|
#endif
|
|
|
|
argv[argc++] = "-DFIB";
|
|
|
|
argv[argc++] = "-run";
|
|
|
|
argv[argc++] = __FILE__;
|
|
|
|
argv[argc++] = b;
|
|
|
|
argv[argc] = NULL;
|
|
|
|
|
|
|
|
s = new_state(1);
|
2019-12-14 14:31:03 +03:00
|
|
|
sleep_ms(2);
|
2019-12-11 02:37:18 +03:00
|
|
|
ret = tcc_add_file(s, argv[0]);
|
2019-12-14 14:31:03 +03:00
|
|
|
sleep_ms(3);
|
2020-01-18 00:58:39 +03:00
|
|
|
if (ret < 0)
|
|
|
|
exit(1);
|
|
|
|
tcc_run(s, argc, argv);
|
2019-12-11 02:37:18 +03:00
|
|
|
tcc_delete(s);
|
2019-12-14 14:31:03 +03:00
|
|
|
fflush(stdout);
|
2019-12-11 02:37:18 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-18 00:58:39 +03:00
|
|
|
void time_tcc(int n, const char *src)
|
2019-12-11 02:37:18 +03:00
|
|
|
{
|
|
|
|
TCCState *s;
|
|
|
|
int ret;
|
|
|
|
while (--n >= 0) {
|
|
|
|
s = new_state(1);
|
2020-01-18 00:58:39 +03:00
|
|
|
ret = tcc_add_file(s, src);
|
2019-12-11 02:37:18 +03:00
|
|
|
tcc_delete(s);
|
|
|
|
if (ret < 0)
|
2020-01-18 00:58:39 +03:00
|
|
|
exit(1);
|
2019-12-11 02:37:18 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned getclock_ms(void)
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
return GetTickCount();
|
|
|
|
#else
|
|
|
|
struct timeval tv;
|
|
|
|
gettimeofday(&tv, NULL);
|
|
|
|
return tv.tv_sec*1000 + (tv.tv_usec+500)/1000;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
unsigned t;
|
|
|
|
|
|
|
|
g_argc = argc;
|
|
|
|
g_argv = argv;
|
|
|
|
|
2020-01-18 00:58:39 +03:00
|
|
|
if (argc < 2) {
|
|
|
|
fprintf(stderr, "usage: libtcc_test_mt tcc.c <options>\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-12-11 02:37:18 +03:00
|
|
|
#if 1
|
2020-04-12 18:34:01 +03:00
|
|
|
printf("mixed calls\n "), fflush(stdout);
|
2019-12-11 02:37:18 +03:00
|
|
|
t = getclock_ms();
|
|
|
|
state_test();
|
|
|
|
printf("\n(%u ms)\n", getclock_ms() - t);
|
|
|
|
#endif
|
|
|
|
#if 1
|
2020-04-12 18:34:01 +03:00
|
|
|
printf("threads\n "), fflush(stdout);
|
2019-12-11 02:37:18 +03:00
|
|
|
t = getclock_ms();
|
|
|
|
for (n = 0; n < M; ++n)
|
|
|
|
create_thread(thread_test_simple, n);
|
|
|
|
wait_threads(n);
|
|
|
|
printf("\n(%u ms)\n", getclock_ms() - t);
|
|
|
|
#endif
|
|
|
|
#if 1
|
2020-04-12 18:34:01 +03:00
|
|
|
printf("tcc in threads\n "), fflush(stdout);
|
2019-12-11 02:37:18 +03:00
|
|
|
t = getclock_ms();
|
|
|
|
for (n = 0; n < M; ++n)
|
|
|
|
create_thread(thread_test_complex, n);
|
|
|
|
wait_threads(n);
|
|
|
|
printf("\n(%u ms)\n", getclock_ms() - t);
|
|
|
|
#endif
|
|
|
|
#if 1
|
2020-04-12 18:34:01 +03:00
|
|
|
printf("compiling tcc 10 times\n"), fflush(stdout);
|
2019-12-11 02:37:18 +03:00
|
|
|
t = getclock_ms();
|
2020-01-18 00:58:39 +03:00
|
|
|
time_tcc(10, argv[1]);
|
2019-12-11 02:37:18 +03:00
|
|
|
printf("(%u ms)\n", (getclock_ms() - t) / 10), fflush(stdout);
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
#include <tcclib.h>
|
|
|
|
int fib(n)
|
|
|
|
{
|
|
|
|
return (n <= 2) ? 1 : fib(n-1) + fib(n-2);
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
printf(" %d", fib(atoi(argv[1]), 2));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|