コード例 #1
0
ファイル: acl_meter_time.c プロジェクト: 10jschen/acl
double acl_meter_time(const char *filename, int line, const char *info)
{
	struct timeval now;
	double  f;
	METER_CTX_T *ctx = tls_calloc(sizeof(METER_CTX_T));

	if (ctx->init_done == 0) {
		ctx->init_done = 1;
		gettimeofday(&ctx->stamp, NULL);
	}

	gettimeofday(&now, NULL);
	now.tv_usec -= ctx->stamp.tv_usec;
	if (now.tv_usec < 0) {
		--now.tv_sec;
		now.tv_usec += 1000000;
	}
	now.tv_sec -= ctx->stamp.tv_sec;

	f = now.tv_sec * 1000.0 + now.tv_usec/1000.0;
	if (info)
		printf("tid=%lu, %s(%d), %s: time inter = %8.3f ms\r\n",
			(unsigned long) acl_pthread_self(), filename, line, info, f);
	else
		printf("tid=%lu, %s(%d): time inter = %8.3f ms\r\n",
			(unsigned long) acl_pthread_self(), filename, line, f);

	gettimeofday(&ctx->stamp, NULL);
	return (f);
}
コード例 #2
0
ファイル: fs_benchmark.cpp プロジェクト: 10jschen/acl
static void thread_main(void*)
{
	printf("%s: thread: %ld\r\n", __FUNCTION__,
		(unsigned long) acl_pthread_self());
	acl::aio_handle* handle;

	// 每个线程创建单独的异步事件句柄
	handle = new acl::aio_handle(__kernel_event ?
		acl::ENGINE_KERNEL : acl::ENGINE_SELECT);

	int i;
	for (i = 0; i < __parallel; i++)
	{
		async_file* fp = new async_file(handle, __path, i);
		if (fp->open_write() == false)
		{
			printf("open file error: %s\r\n", acl::last_serror());
			delete fp;
			break;
		}
	}

	if (i == 0)
	{
		printf("thread(%lu) no file opened!\r\n", (unsigned long)
			acl_pthread_self());
		delete handle;
		return;
	}

	// 进入异步事件循环过程
	while (true)
	{
		if (handle->check() == false)
			break;
		if (__nok == __parallel)
		{
			printf("%s: thread(%lu) over, total: %d\r\n", __FUNCTION__,
				(unsigned long) acl_pthread_self(), __nok);
			break;
		}
	}

	// 因为 IO 句柄是延迟释放的,所以需要再次检查一遍
	handle->check();

	// 销毁异步事件句柄
	delete handle;
}
コード例 #3
0
ファイル: master_service.cpp プロジェクト: 10jschen/acl
bool master_service::thread_on_read(acl::socket_stream* stream)
{
	logger("thread id: %lu", acl_pthread_self());

	acl::http_response res(stream);
	// 响应数据体为 xml 格式
	res.response_header().set_content_type("text/html");

	// 读 HTTP 请求头
	if (res.read_header() == false)
		return false;

	acl::string buf;
	// 读 HTTP 请求体数据
	if (res.get_body(buf) == false)
		return false;

	acl::http_client* client = res.get_client();

	// 判断客户端是否希望保持长连接
	bool keep_alive = client->keep_alive();

	// 返回数据给客户端

	res.response_header()
		.set_status(200)
		.set_keep_alive(keep_alive)
		.set_content_length(var_cfg_buf_size);

	if (res.response(res_buf_, var_cfg_buf_size) == false)
		return false;

	return keep_alive ? true : false;
}
コード例 #4
0
ファイル: master_service.cpp プロジェクト: 10jschen/acl
bool master_service::thread_on_accept(acl::socket_stream* conn)
{
	if (0)
		acl_tcp_so_linger(conn->sock_handle(), 1, 0);
	logger("thread id: %lu", acl_pthread_self());
	return true;
}
コード例 #5
0
ファイル: fiber_io.c プロジェクト: QianErGe/acl
void fiber_io_check(void)
{
	if (__thread_fiber != NULL)
		return;

	acl_assert(acl_pthread_once(&__once_control, thread_init) == 0);

	__maxfd = acl_open_limit(0);
	if (__maxfd <= 0)
		__maxfd = MAXFD;

	__thread_fiber = (FIBER_TLS *) acl_mymalloc(sizeof(FIBER_TLS));
	__thread_fiber->event = event_create(__maxfd);
	__thread_fiber->io_fibers = (ACL_FIBER **)
		acl_mycalloc(__maxfd, sizeof(ACL_FIBER *));
	__thread_fiber->ev_fiber = acl_fiber_create(fiber_io_loop,
			__thread_fiber->event, STACK_SIZE);
	__thread_fiber->io_count = 0;
	__thread_fiber->nsleeping = 0;
	__thread_fiber->io_stop = 0;
	acl_ring_init(&__thread_fiber->ev_timer);

	if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) {
		__main_fiber = __thread_fiber;
		atexit(fiber_io_main_free);
	} else if (acl_pthread_setspecific(__fiber_key, __thread_fiber) != 0)
		acl_msg_fatal("acl_pthread_setspecific error!");
}
コード例 #6
0
ファイル: fiber_sem.c プロジェクト: LazyPlanet/acl
int acl_fiber_sem_wait(ACL_FIBER_SEM *sem)
{
	ACL_FIBER *curr;

	if (sem->tid != acl_pthread_self())
		return -1;

	if (sem->num > 0) {
		sem->num--;
		return sem->num;
	}

	curr = acl_fiber_running();
	if (curr == NULL)
		return -1;

	acl_ring_prepend(&sem->waiting, &curr->me);
	acl_fiber_switch();

	/* if switch to me because other killed me, I should detach myself;
	 * else if because other unlock, I'll be detached twice which is
	 * hamless because ACL_RING can deal with it.
	 */
	acl_ring_detach(&curr->me);

	return sem->num;
}
コード例 #7
0
static void fiber_check(void)
{
	if (__thread_fiber != NULL)
		return;

	acl_assert(acl_pthread_once(&__once_control, thread_init) == 0);

	__thread_fiber = (FIBER_TLS *) acl_mycalloc(1, sizeof(FIBER_TLS));
#ifdef	USE_JMP
	/* set context NULL when using setjmp that setcontext will not be
	 * called in fiber_swap.
	 */
	__thread_fiber->original.context = NULL;
#else
	__thread_fiber->original.context = (ucontext_t *)
		acl_mycalloc(1, sizeof(ucontext_t));
#endif
	__thread_fiber->fibers = NULL;
	__thread_fiber->size   = 0;
	__thread_fiber->slot   = 0;
	__thread_fiber->idgen  = 0;
	__thread_fiber->count  = 0;

	acl_ring_init(&__thread_fiber->ready);
	acl_ring_init(&__thread_fiber->dead);

	if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) {
		__main_fiber = __thread_fiber;
		atexit(fiber_schedule_main_free);
	} else if (acl_pthread_setspecific(__fiber_key, __thread_fiber) != 0)
		acl_msg_fatal("acl_pthread_setspecific error!");
}
コード例 #8
0
ファイル: icmp_chat.c プロジェクト: 1514louluo/acl
ICMP_CHAT *icmp_chat_create(ACL_AIO* aio, int check_tid)
{
	ICMP_CHAT *chat;

	chat = (ICMP_CHAT*) acl_mycalloc(1, sizeof(ICMP_CHAT));
	chat->aio = aio;
	acl_ring_init(&chat->host_head);
	chat->is = icmp_stream_open(aio);
	chat->seq_no = 0;
	chat->count = 0;
#ifdef ACL_UNIX
	chat->pid = getpid();
#elif defined(ACL_WINDOWS)
	chat->pid = _getpid();
#endif
	chat->tid = (unsigned long) acl_pthread_self();
	chat->check_tid = check_tid;

	if (aio != NULL)
		icmp_chat_aio_init(chat, aio);
	else
		icmp_chat_sio_init(chat);

	return (chat);
}
コード例 #9
0
ファイル: master_service.cpp プロジェクト: putaozhuose/acl
bool master_service::thread_on_read(acl::socket_stream* conn)
{
	http_servlet* servlet = (http_servlet*) conn->get_ctx();
	if (servlet == NULL)
		logger_fatal("servlet null!");

	if (conf_ == NULL)
		return servlet->doRun("127.0.0.1:11211", conn);

	acl::stream_hook* hook = conn->get_hook();
	if (hook != NULL)
		return servlet->doRun("127.0.0.1:11211", conn);

	// 对于使用 SSL 方式的流对象,需要将 SSL IO 流对象注册至网络
	// 连接流对象中,即用 ssl io 替换 stream 中默认的底层 IO 过程

	logger("begin setup ssl hook...");

	acl::polarssl_io* ssl = new acl::polarssl_io(*conf_, true);
	if (conn->setup_hook(ssl) == ssl)
	{
		logger_error("setup_hook error!");
		ssl->destroy();
		return false;
	}

	logger("setup hook ok, tid: %lu", (unsigned long) acl_pthread_self());

	return servlet->doRun("127.0.0.1:11211", conn);
}
コード例 #10
0
ファイル: main.cpp プロジェクト: bygreencn/acl
static void free_buf_fn(void *arg)
{
	ACL_VSTRING *buf = (ACL_VSTRING*) arg;

	printf(">> current thread id=%u, buf = %s\r\n",
		(unsigned int) acl_pthread_self(), acl_vstring_str(buf));
	acl_vstring_free(buf);
}
コード例 #11
0
ファイル: main.c プロジェクト: 10jschen/acl
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());
}
コード例 #12
0
ファイル: gettimeofday.c プロジェクト: bygreencn/acl
static void once_init(void)
{
	if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) {
		acl_pthread_key_create(&once_key, dummy);
		atexit(main_free_tls);
	} else
		acl_pthread_key_create(&once_key, free_tls);
}
コード例 #13
0
ファイル: main.cpp プロジェクト: bygreencn/acl
static void main_thread_atexit(void *arg)
{
	ACL_VSTRING *buf = (ACL_VSTRING*) arg;

	printf("main thread exit now, tid=%u, buf=%s\r\n",
		(unsigned int) acl_pthread_self(), acl_vstring_str(buf));
	printf("in the main thread_atexit, input any key to exit\r\n");
	getchar();
}
コード例 #14
0
ファイル: main.c プロジェクト: 10jschen/acl
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);
}
コード例 #15
0
ファイル: main.cpp プロジェクト: bygreencn/acl
static void on_thread_exit(void *arg)
{
	const char *myname = "on_thread_exit";
	acl_pthread_pool_t *thr_pool = (acl_pthread_pool_t*) arg;

	/* 判断一下,仅是为了验证参数传递过程 */
	assert(thr_pool == __thr_pool);
	printf("%s: thread(%u) exit now\r\n", myname, (unsigned int) acl_pthread_self());
}
コード例 #16
0
ファイル: main.cpp プロジェクト: 2202877/acl
// 子线程处理过程
static void thread_main(void*)
{
	for (int i = 0; i < __loop_count; i++)
	{
		connect_pool* pool = (connect_pool*) __conn_manager->peek();
		if (pool == NULL)
		{
			printf("\r\n>>>%lu(%d): peek pool failed<<<\r\n",
				(unsigned long) acl_pthread_self(), __LINE__);
			check_all_connections();
			exit (1);
		}

		// 设置连接的超时时间及读超时时间
		pool->set_timeout(2, 2);

		// 从连接池中获取一个连接
		connect_client* conn = (connect_client*) pool->peek();
		if (conn == NULL)
		{
			printf("\r\n>>>%lu: peek connect failed from %s<<<\r\n",
				(unsigned long) acl_pthread_self(),
				pool->get_addr());
			check_all_connections();
			exit (1);
		}

		// 需要对获得的连接重置状态,以清除上次请求过程的临时数据
		else
			conn->reset();

		// 开始新的 HTTP 请求过程
		if (get(conn, i) == false)
		{
			printf("one request failed, close connection\r\n");
			// 错误连接需要关闭
			pool->put(conn, false);
		}
		else
			pool->put(conn, true);
	}

	printf(">>>>thread: %lu OVER<<<<\r\n", (unsigned long) acl_pthread_self());
}
コード例 #17
0
ファイル: fiber_sem.c プロジェクト: LazyPlanet/acl
ACL_FIBER_SEM *acl_fiber_sem_create(int num)
{
	ACL_FIBER_SEM *sem = (ACL_FIBER_SEM *)
		acl_mymalloc(sizeof(ACL_FIBER_SEM));

	sem->num = num;
	acl_ring_init(&sem->waiting);
	sem->tid = acl_pthread_self();
	return sem;
}
コード例 #18
0
ファイル: db_mysql.cpp プロジェクト: iYefeng/acl
static void thread_free_dummy(void* ctx)
{
	if ((unsigned long) acl_pthread_self() != acl_main_thread_self())
		acl_myfree(ctx);

#ifdef HAS_MYSQL_DLL
	if (__mysql_thread_end)
		__mysql_thread_end();
#endif
}
コード例 #19
0
ファイル: acl_read_wait.c プロジェクト: gnuhub/redis-1
int acl_read_wait(ACL_SOCKET fd, int timeout)
{
	const char *myname = "acl_read_wait";
	int op = EPOLL_CTL_ADD, delay = timeout * 1000, *epoll_fd;
	struct epoll_event ee, events[1];

	acl_assert(acl_pthread_once(&epoll_once, thread_epoll_init) == 0);
	epoll_fd = (int*) acl_pthread_getspecific(epoll_key);
	if (epoll_fd == NULL) {
		epoll_fd = (int*) acl_mymalloc(sizeof(int));
		acl_assert(acl_pthread_setspecific(epoll_key, epoll_fd) == 0);
		if ((unsigned long) acl_pthread_self()
			== acl_main_thread_self())
		{
			main_epoll_read_fd = epoll_fd;
			atexit(main_epoll_end);
		}

		*epoll_fd = epoll_create(1);
	}

	ee.events = EPOLLIN | EPOLLHUP | EPOLLERR;
	ee.data.u64 = 0;
	ee.data.fd = fd;
	if (epoll_ctl(*epoll_fd, op, fd, &ee) == -1) {
		acl_msg_error("%s(%d): epoll_ctl error: %s, fd: %d",
			myname, __LINE__, acl_last_serror(), fd);
		return -1;
	}

	if (epoll_wait(*epoll_fd, events, 1, delay) == -1) {
		acl_msg_error("%s(%d): epoll_wait error: %s, fd: %d",
			myname, __LINE__, acl_last_serror(), fd);
		return -1;
	}

	if ((events[0].events & (EPOLLERR | EPOLLHUP)) != 0)
		return -1;

	if ((events[0].events & EPOLLIN) == 0) {
		acl_set_error(ACL_ETIMEDOUT);
		return -1;
	}

	ee.events = 0;
	ee.data.u64 = 0;
	ee.data.fd = fd;
	if (epoll_ctl(*epoll_fd, EPOLL_CTL_DEL, fd, &ee) == -1) {
		acl_msg_error("%s(%d): epoll_ctl error: %s, fd: %d",
			myname, __LINE__, acl_last_serror(), fd);
		return -1;
	}

	return 0;
}
コード例 #20
0
ファイル: acl_mem_slice.c プロジェクト: LazyPlanet/acl
static void slice_key_init(void)
{
	unsigned long curr_tid = (unsigned long) acl_pthread_self();
	unsigned long main_tid = (unsigned long) acl_main_thread_self();

	if (curr_tid == main_tid) {
		acl_pthread_key_create(&__mem_slice_key, NULL);
		atexit(main_thread_slice_free);
	} else
		acl_pthread_key_create(&__mem_slice_key, (void (*)(void*)) mem_slice_free);
}
コード例 #21
0
ファイル: acl_mem_slice.c プロジェクト: LazyPlanet/acl
static ACL_MEM_SLICE *mem_slice_create(void)
{
	const char *myname = "mem_slice_create";
	ACL_MEM_SLICE *mem_slice;

	acl_pthread_once(&once_control, slice_key_init);

	if (__mem_slice_key == (acl_pthread_key_t) -1)
		acl_msg_fatal("%s(%d): __mem_slice_key(%d) invalid,"
			" call acl_mem_slice_init or acl_mem_slice_set first",
			myname, __LINE__, (int) __mem_slice_key);

	mem_slice = acl_pthread_getspecific(__mem_slice_key);
	if (mem_slice != NULL)
		return mem_slice;

	mem_slice = (ACL_MEM_SLICE*)
		acl_default_calloc(__FILE__, __LINE__, 1, sizeof(ACL_MEM_SLICE));
	if (mem_slice == NULL)
		acl_msg_fatal("%s(%d): can't alloc for mem_slice(%s)",
			myname, __LINE__, acl_last_serror());

	mem_slice->slice_pool = acl_slice_pool_create(__mem_base,
			__mem_nslice, __mem_slice_flag);
	mem_slice->tid = (unsigned long) acl_pthread_self();
	mem_slice->list = private_array_create(__mem_list_init_size);
	MUTEX_INIT(mem_slice);
	mem_slice->tls_key = __mem_slice_key;
	mem_slice->nalloc_gc = __mem_nalloc_gc;
	mem_slice->slice_flag = __mem_slice_flag;

	acl_pthread_setspecific(__mem_slice_key, mem_slice);

	if ((unsigned long) acl_pthread_self() == acl_main_thread_self())
		__main_mem_slice = mem_slice;

	acl_msg_info("%s(%d): thread(%ld) set myown mem_slice(%p)",
		myname, __LINE__, (long) mem_slice->tid, mem_slice);

	return mem_slice;
}
コード例 #22
0
ファイル: main.cpp プロジェクト: bygreencn/acl
static int on_thread_init(void *arg)
{
	const char *myname = "on_thread_init";
	acl_pthread_pool_t *thr_pool = (acl_pthread_pool_t*) arg;

	/* 判断一下,仅是为了验证参数传递过程 */
	assert(thr_pool == __thr_pool);
	printf("%s: thread(%u) init now\r\n", myname, (unsigned int) acl_pthread_self());

	/* 返回0表示继续执行该线程获得的新任务,返回-1表示停止执行该任务 */
	return (0);
}
コード例 #23
0
ファイル: acl_mem_slice.c プロジェクト: LazyPlanet/acl
void acl_mem_slice_destroy(void)
{
	ACL_MEM_SLICE *mem_slice = acl_pthread_getspecific(__mem_slice_key);

	if (mem_slice == NULL)
		return;
	/* 释放该线程所拥有的内存切片池对象 */
	mem_slice_free(mem_slice);
	acl_pthread_setspecific(__mem_slice_key, NULL);
	if ((unsigned long) acl_pthread_self() == acl_main_thread_self())
		__main_mem_slice = NULL;
}
コード例 #24
0
ファイル: fiber_sem.c プロジェクト: LazyPlanet/acl
int acl_fiber_sem_trywait(ACL_FIBER_SEM *sem)
{
	if (sem->tid != acl_pthread_self())
		return -1;

	if (sem->num > 0) {
		sem->num--;
		return sem->num;
	}

	return -1;
}
コード例 #25
0
ファイル: acl_read_wait.c プロジェクト: xmszt/acl
static void thread_epoll_end(void *ctx)
{
    const char *myname = "thread_epoll_end";
    EPOLL_CTX *epoll_ctx = (EPOLL_CTX*) ctx;

    acl_msg_info("%s(%d), %s: close epoll_fd: %d, tid: %lu, %lu",
                 __FILE__, __LINE__, myname, epoll_ctx->epfd,
                 epoll_ctx->tid, acl_pthread_self());

    close(epoll_ctx->epfd);
    acl_myfree(epoll_ctx);
}
コード例 #26
0
ファイル: master_service.cpp プロジェクト: 10jschen/acl
void master_service::proc_on_init()
{
	logger("thread id: %lu", acl_pthread_self());

	if (var_cfg_buf_size <= 0)
		var_cfg_buf_size = 1024;
	res_buf_ = (char*) acl_mymalloc(var_cfg_buf_size + 1);
	int i;
	for (i = 0; i < var_cfg_buf_size; i++)
		res_buf_[i] = 'X';
	res_buf_[i] = 0;
}
コード例 #27
0
ファイル: main.cpp プロジェクト: bygreencn/acl
static void worker_thread(void *arg)
{
	THREAD_CTX *ctx = (THREAD_CTX*) arg; /* 获得用户自定义对象 */
	unsigned int   i = 0;
	static __thread ACL_VSTRING *buf1 = NULL;
	static __thread ACL_VSTRING *buf2 = NULL;

	/* 仅是验证参数传递过程 */
	assert(ctx->thr_pool == __thr_pool);

	if (buf1 == NULL)
		buf1 = acl_vstring_alloc(256);
	if (buf2 == NULL)
		buf2 = acl_vstring_alloc(256);

	acl_vstring_sprintf(buf1, "buf1: tid=%u",
		(unsigned int) acl_pthread_self());
	acl_vstring_sprintf(buf2, "buf2: tid=%u",
		(unsigned int) acl_pthread_self());
	/* 注册函数,当该线程退出时自动释放 buf 内存空间 */
	acl_pthread_atexit_add(buf1, free_buf_fn);
	acl_pthread_atexit_add(buf2, free_buf_fn);

	while (i < 5) {
		if (__local != i)
			acl_msg_fatal("__local=%d invalid", __local);
		printf("thread id=%u, i=%d, __local=%d\r\n",
			(unsigned int) acl_pthread_self(), ctx->i, __local);
		i++;
		/* 在本线程中将线程局部变量加1 */
		__local++;
		sleep(1);
	}

	acl_myfree(ctx);

	/* 至此,该工作线程进入空闲状态,直到空闲超时退出 */
}
コード例 #28
0
ファイル: acl_pthread.c プロジェクト: LazyPlanet/acl
static DWORD WINAPI RunThreadWrap(LPVOID data)
#endif
{
	acl_pthread_t *thread = (acl_pthread_t *) data;
	void *return_arg;
	ACL_FIFO *tls_value_list_ptr = tls_value_list_get();
	unsigned long *tid = 0;

	/* 只是为了避免与主线程的 h_thread->handle = handle 产生冲突 */
	if (__thread_inited)
		acl_pthread_mutex_lock(&__thread_lock);
	if (__thread_inited)
		acl_pthread_mutex_unlock(&__thread_lock);

	thread->id = acl_pthread_self();

	return_arg = (void*) thread->start_routine(thread->routine_arg);

	/* 释放由 acl_pthread_setspecific 添加的线程局部变量 */
	while (1) {
		TLS_VALUE *tls_value = private_fifo_pop(tls_value_list_ptr);

		if (tls_value == NULL)
			break;

		if (tls_value->tls_key == NULL
			|| tls_value->tls_key->destructor == NULL
			|| tls_value->tls_key->key < 0
			|| tls_value->tls_key->key >= ACL_PTHREAD_KEYS_MAX)
		{
			acl_default_free(__FILE__, __LINE__, tls_value);
			continue;
		}
		tls_value->tls_key->destructor(tls_value->value);
		acl_default_free(__FILE__, __LINE__, tls_value);
	}

	private_fifo_free(tls_value_list_ptr, NULL);

	/* 如果线程创建时为分离方式则需要关闭线程句柄 */
	if (thread->detached) {
		if (!CloseHandle(thread->handle)) {
			acl_msg_error("close handle error(%s)", 
				acl_last_serror());
		}
	}

	acl_default_free(__FILE__, __LINE__, thread);
	return (DWORD) return_arg;
}
コード例 #29
0
ファイル: acl_read_wait.c プロジェクト: xmszt/acl
static void main_epoll_end(void)
{
    const char *myname = "main_epoll_end";

    if (main_epoll_ctx != NULL) {
        acl_msg_info("%s(%d), %s: close epoll_fd: %d, tid: %lu, %lu",
                     __FILE__, __LINE__, myname, main_epoll_ctx->epfd,
                     main_epoll_ctx->tid, acl_pthread_self());

        close(main_epoll_ctx->epfd);
        acl_myfree(main_epoll_ctx);
        main_epoll_ctx = NULL;
    }
}
コード例 #30
0
ファイル: gettimeofday.c プロジェクト: bygreencn/acl
static void *tls_calloc(size_t len)
{
	void *ptr;

	(void) acl_pthread_once(&once_control, once_init);
	ptr = (void*) acl_pthread_getspecific(once_key);
	if (ptr == NULL) {
		ptr = acl_mycalloc(1, len);
		acl_pthread_setspecific(once_key, ptr);
		if ((unsigned long) acl_pthread_self() == acl_main_thread_self())
			__tls = ptr;
	}
	return ptr;
}