2014-11-18 23:08:34 +08:00
|
|
|
|
|
|
|
#include "stdlib/acl_define_unix.h"
|
|
|
|
#ifdef ACL_UNIX
|
|
|
|
# ifndef _GNU_SOURCE
|
|
|
|
# define _GNU_SOURCE
|
|
|
|
# endif
|
|
|
|
# include <pthread.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "lib_acl.h"
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
typedef struct THREAD_CTX {
|
|
|
|
int i;
|
|
|
|
} THREAD_CTX;
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
typedef volatile int pthread_spinlock_t;
|
|
|
|
extern int pthread_spin_init (pthread_spinlock_t *__lock, int __pshared);
|
|
|
|
extern int pthread_spin_lock (pthread_spinlock_t *__lock);
|
|
|
|
extern int pthread_spin_unlock (pthread_spinlock_t *__lock);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void *test_thread_fn(void *arg)
|
|
|
|
{
|
|
|
|
THREAD_CTX *ctx = (THREAD_CTX*) arg;
|
|
|
|
|
|
|
|
ctx->i++;
|
|
|
|
printf("current tid is: %lu\r\n", (unsigned long int) acl_pthread_self());
|
|
|
|
|
|
|
|
return (ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ACL_UNIX
|
|
|
|
static pthread_spinlock_t __spin_lock;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void *thread_nested_mutex(void *arg)
|
|
|
|
{
|
|
|
|
acl_pthread_mutex_t *mutex = (acl_pthread_mutex_t*) arg;
|
|
|
|
int m = 2;
|
|
|
|
int i, n = 100000000;
|
|
|
|
time_t begin, end;
|
|
|
|
|
|
|
|
#ifdef ACL_UNIX
|
|
|
|
if (0) {
|
|
|
|
printf("tid: %lu, begin spin lock\n", (unsigned long int) acl_pthread_self());
|
|
|
|
|
|
|
|
time(&begin);
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
pthread_spin_lock(&__spin_lock);
|
|
|
|
pthread_spin_unlock(&__spin_lock);
|
|
|
|
}
|
|
|
|
time(&end);
|
|
|
|
printf("tid: %lu, lock over, spin, time: %ld\n",
|
|
|
|
(unsigned long int) acl_pthread_self(), (long) end - begin);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (1) {
|
|
|
|
printf("tid: %lu, begin lock mutex\n",
|
|
|
|
(unsigned long int) acl_pthread_self());
|
|
|
|
time(&begin);
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
acl_thread_mutex_lock(mutex);
|
|
|
|
acl_thread_mutex_unlock(mutex);
|
|
|
|
}
|
|
|
|
time(&end);
|
|
|
|
printf("tid: %lu, lock mutex ok, nested: %d, sleep %d seconds, time: %ld\n",
|
|
|
|
(unsigned long int) acl_pthread_self(),
|
|
|
|
acl_thread_mutex_nested(mutex), m, (long) end - begin);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (0) {
|
|
|
|
sleep(m);
|
|
|
|
printf("tid: %lu, wakeup, begin unlock\n",
|
|
|
|
(unsigned long int) acl_pthread_self());
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
acl_thread_mutex_unlock(mutex);
|
|
|
|
time(&end);
|
|
|
|
printf("tid: %lu, time: %ld, exit now\n",
|
|
|
|
(unsigned long int) acl_pthread_self(), (long) end - begin);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_nested_mutex(void)
|
|
|
|
{
|
|
|
|
acl_pthread_t tid;
|
|
|
|
acl_pthread_attr_t attr;
|
|
|
|
static acl_pthread_mutex_t mutex;
|
|
|
|
|
|
|
|
#ifdef ACL_UNIX
|
|
|
|
pthread_spin_init(&__spin_lock, 0);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
acl_pthread_mutex_init(&mutex, NULL);
|
|
|
|
acl_pthread_attr_init(&attr);
|
|
|
|
acl_pthread_attr_setdetachstate(&attr, ACL_PTHREAD_CREATE_DETACHED);
|
|
|
|
acl_pthread_create(&tid, &attr, thread_nested_mutex, &mutex);
|
|
|
|
acl_pthread_create(&tid, &attr, thread_nested_mutex, &mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ACL_UNIX
|
|
|
|
static pthread_mutex_t mutex_init1 = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
static pthread_mutex_t mutex_init2 = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
|
|
|
|
static void test_thread(void)
|
|
|
|
{
|
|
|
|
acl_pthread_t tid;
|
|
|
|
acl_pthread_attr_t attr;
|
|
|
|
THREAD_CTX ctx, *pctx;
|
|
|
|
void *return_arg;
|
|
|
|
unsigned int id;
|
|
|
|
|
|
|
|
acl_pthread_mutex_lock(&mutex_init1);
|
|
|
|
printf("lock mutex_init1 ok\n");
|
|
|
|
acl_pthread_mutex_lock(&mutex_init2);
|
|
|
|
printf("lock mutex_init2 ok\n");
|
|
|
|
|
|
|
|
ctx.i = 0;
|
|
|
|
acl_pthread_attr_init(&attr);
|
|
|
|
acl_pthread_create(&tid, &attr, test_thread_fn, &ctx);
|
|
|
|
acl_pthread_join(tid, (void**) &return_arg);
|
|
|
|
pctx = (THREAD_CTX*) return_arg;
|
|
|
|
memcpy(&id, &tid, sizeof(id));
|
|
|
|
printf("ctx.i=%d, pctx->i=%d, the thread id is: %u\r\n",
|
|
|
|
ctx.i, pctx->i, id);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void free_vstring(void *arg)
|
|
|
|
{
|
|
|
|
const char *myname = "free_vstring";
|
|
|
|
ACL_VSTRING *buf = (ACL_VSTRING*) arg;
|
|
|
|
|
|
|
|
acl_vstring_free(buf);
|
|
|
|
printf("%s: tid=%d, free vstring ok\n", myname, (int) acl_pthread_self());
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *test_tls_thread(void *arg acl_unused)
|
|
|
|
{
|
|
|
|
const char *myname = "test_tls_thread";
|
|
|
|
static acl_pthread_key_t key = -1;
|
|
|
|
ACL_VSTRING *buf;
|
|
|
|
time_t begin;
|
|
|
|
int i;
|
|
|
|
unsigned long tid;
|
|
|
|
const char *p = acl_last_serror();
|
|
|
|
|
|
|
|
printf("%s(%d): last serror: %s, %p\n", myname, __LINE__, p, p);
|
|
|
|
|
|
|
|
printf(">>>%s(%d)(tid=%d): key = %d\n", myname, __LINE__, (int) acl_pthread_self(), key);
|
|
|
|
sleep(1);
|
|
|
|
printf(">>>%s(%d)(tid=%d): key = %d\n", myname, __LINE__, (int) acl_pthread_self(), key);
|
|
|
|
if (1) {
|
|
|
|
time(&begin);
|
|
|
|
for (i = 0; i < 10000000; i++) {
|
|
|
|
buf = acl_pthread_tls_get(&key);
|
|
|
|
if (buf == NULL) {
|
|
|
|
printf(">>>%s(tid=%d): buf null, key = %d\n",
|
|
|
|
myname, (int) acl_pthread_self(), key);
|
|
|
|
buf = acl_vstring_alloc(256);
|
|
|
|
acl_pthread_tls_set(key, buf, free_vstring);
|
|
|
|
}
|
|
|
|
tid = acl_pthread_self();
|
|
|
|
}
|
|
|
|
printf(">>>%s(%d)(tid=%d): time cose %d seconds, tid: %ld\n",
|
|
|
|
myname, __LINE__, (int) acl_pthread_self(),
|
|
|
|
(int) (time(NULL) - begin), tid);
|
|
|
|
acl_vstring_sprintf(buf, "%s, tid=%lu", myname, (unsigned long) acl_pthread_self());
|
|
|
|
printf(">>>%s: buf=%s\n", myname, acl_vstring_str(buf));
|
|
|
|
} else {
|
|
|
|
time(&begin);
|
|
|
|
for (i = 0; i < 1000000; i++) {
|
|
|
|
buf = acl_vstring_alloc(256);
|
|
|
|
acl_vstring_free(buf);
|
|
|
|
}
|
|
|
|
printf(">>>%s(%d)(tid=%d): time cose %d seconds\n",
|
|
|
|
myname, __LINE__, (int) acl_pthread_self(),
|
|
|
|
(int) (time(NULL) - begin));
|
|
|
|
}
|
|
|
|
sleep(1);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_tls(void)
|
|
|
|
{
|
|
|
|
acl_pthread_attr_t attr;
|
|
|
|
acl_pthread_t t1, t2;
|
|
|
|
|
|
|
|
acl_pthread_attr_init(&attr);
|
|
|
|
acl_pthread_create(&t1, &attr, test_tls_thread, NULL);
|
|
|
|
acl_pthread_create(&t2, &attr, test_tls_thread, NULL);
|
|
|
|
acl_pthread_join(t1, NULL);
|
|
|
|
acl_pthread_join(t2, NULL);
|
|
|
|
printf(">>> test_tls: over now\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __init_once_key = 0;
|
|
|
|
static void init_once(void)
|
|
|
|
{
|
|
|
|
const char *myname = "init_once";
|
|
|
|
|
|
|
|
__init_once_key++;
|
|
|
|
printf("%s(%d, tid=%d): __init_once_key=%d\n",
|
|
|
|
myname, __LINE__, (int) acl_pthread_self(), __init_once_key);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free_buf(void *ctx)
|
|
|
|
{
|
|
|
|
ACL_VSTRING *buf = (ACL_VSTRING*) ctx;
|
|
|
|
acl_vstring_free(buf);
|
|
|
|
printf(">>>>%s(tid=%d): free vstring ok\n",
|
|
|
|
__FUNCTION__, (int) acl_pthread_self());
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free_vbuf(void *ctx)
|
|
|
|
{
|
|
|
|
ACL_VSTRING *buf = (ACL_VSTRING*) ctx;
|
|
|
|
acl_vstring_free(buf);
|
|
|
|
printf(">>>>%s(tid=%d): free vstring ok\n",
|
|
|
|
__FUNCTION__, (int) acl_pthread_self());
|
|
|
|
}
|
|
|
|
|
|
|
|
static acl_pthread_once_t once_control = ACL_PTHREAD_ONCE_INIT;
|
|
|
|
static void *test_once_thread(void *arg acl_unused)
|
|
|
|
{
|
|
|
|
ACL_VSTRING *buf;
|
|
|
|
static acl_pthread_key_t buf_key = -1;
|
|
|
|
static __thread ACL_VSTRING *__vbuf = NULL;
|
|
|
|
|
|
|
|
acl_pthread_once(&once_control, init_once);
|
|
|
|
|
|
|
|
if (__vbuf == NULL) {
|
|
|
|
__vbuf = acl_vstring_alloc(256);
|
|
|
|
acl_pthread_atexit_add(__vbuf, free_vbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = (ACL_VSTRING*) acl_pthread_tls_get(&buf_key);
|
|
|
|
if (buf == NULL) {
|
|
|
|
buf = acl_vstring_alloc(256);
|
|
|
|
acl_pthread_tls_set(buf_key, buf, free_buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = (ACL_VSTRING*) acl_pthread_tls_get(&buf_key);
|
|
|
|
if (buf == NULL)
|
|
|
|
printf(">>>%s(tid=%d) buf null\n", __FUNCTION__, (int) acl_pthread_self());
|
|
|
|
else
|
|
|
|
printf(">>>%s(tid=%d) buf not null\n", __FUNCTION__, (int) acl_pthread_self());
|
|
|
|
|
|
|
|
printf(">>>%s: in thread %d, last error: %s\n",
|
|
|
|
__FUNCTION__, (int) acl_pthread_self(), acl_last_serror());
|
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_pthread_once(void)
|
|
|
|
{
|
|
|
|
acl_pthread_attr_t attr;
|
|
|
|
acl_pthread_t t1, t2;
|
|
|
|
|
|
|
|
acl_pthread_attr_init(&attr);
|
|
|
|
acl_pthread_attr_setstacksize(&attr, 10240000);
|
|
|
|
acl_pthread_create(&t1, &attr, test_once_thread, NULL);
|
|
|
|
acl_pthread_create(&t2, &attr, test_once_thread, NULL);
|
|
|
|
acl_pthread_join(t1, NULL);
|
|
|
|
acl_pthread_join(t2, NULL);
|
|
|
|
printf(">>> test_pthread_once: over now, enter any key to exit...\n");
|
|
|
|
getchar();
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc acl_unused, char *argv[] acl_unused)
|
|
|
|
{
|
|
|
|
if (0) {
|
|
|
|
test_pthread_once();
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("%s(%d): last serror: %s, %p\n", __FUNCTION__, __LINE__,
|
|
|
|
acl_last_serror(), acl_last_serror());
|
|
|
|
if (0) {
|
|
|
|
test_tls();
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ACL_UNIX
|
|
|
|
test_thread();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
printf(">>>>main tid: %u\n", (unsigned) acl_pthread_self());
|
|
|
|
if (0)
|
|
|
|
test_nested_mutex();
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
sleep(10);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|