mirror of
https://gitee.com/acl-dev/acl.git
synced 2024-11-29 18:37:41 +08:00
修复了线程池中BUG;修复了iocp及win32消息事件引擎的BUG
This commit is contained in:
parent
b20e0b6c53
commit
9a016e24b1
2
Makefile
2
Makefile
@ -42,7 +42,7 @@ endif
|
||||
##############################################################################
|
||||
|
||||
.PHONY = check help all clean install uninstall uninstall_all build_bin build_src
|
||||
VERSION = 3.0.11
|
||||
VERSION = 3.0.17
|
||||
|
||||
help:
|
||||
@(echo "usage: make help|all|clean|install|uninstall|uninstall_all|build_bin|build_src")
|
||||
|
@ -1,5 +1,6 @@
|
||||
修改历史列表:
|
||||
------------------------------------------------------------------------
|
||||
67) 2014.2.21 --- acl 3.0.17 版本发布!(因线程池库存在严重 BUG,所以发布此紧急版本)
|
||||
66) 2014.2.17 --- acl 3.0.16 版本发布!
|
||||
65) 2014.1.25 --- acl 3.0.15 版本发布!
|
||||
64) 2014.1.11
|
||||
|
@ -1,5 +1,13 @@
|
||||
修改历史列表:
|
||||
|
||||
------------------------------------------------------------------------
|
||||
427) 2014.2.21
|
||||
427.1) bugfix: events_wmsg.c 中在回调函数中没有将 stream 流针对传递,这会影响
|
||||
基于 win32 消息事件的异步 IO 过程
|
||||
427.2) bugfix: events_iocp.c 当主动关闭完成端口时,对于未决状态,不应提前释放
|
||||
重叠结构对象(http://support.microsoft.com/kb/192800/zh-cn)
|
||||
427.3) bugfix: acl_pthread_pool.c 线程条件变量链表的操作方法存在指针越界问题
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
426) 2014.2.17
|
||||
|
@ -53,8 +53,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,1,2,9
|
||||
PRODUCTVERSION 2,1,2,9
|
||||
FILEVERSION 3,0,1,7
|
||||
PRODUCTVERSION 3,0,1,7
|
||||
FILEFLAGSMASK 0x17L
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@ -71,12 +71,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "Comments", "本库为跨平台的C库,包括了网络通讯,服务器框架等功能"
|
||||
VALUE "FileDescription", "acl 库"
|
||||
VALUE "FileVersion", "2, 1, 2, 9"
|
||||
VALUE "FileVersion", "3, 0, 1, 7"
|
||||
VALUE "InternalName", "lib_acl"
|
||||
VALUE "LegalCopyright", "zsx (C) 2011"
|
||||
VALUE "OriginalFilename", "lib_acl.lib"
|
||||
VALUE "ProductName", " acl 库"
|
||||
VALUE "ProductVersion", "2, 1, 2, 9"
|
||||
VALUE "ProductVersion", "3, 0, l, 7"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
@ -50,6 +50,8 @@ struct IOCP_EVENT {
|
||||
int type;
|
||||
#define IOCP_EVENT_READ (1 << 0)
|
||||
#define IOCP_EVENT_WRITE (1 << 2)
|
||||
#define IOCP_EVENT_DEAD (1 << 3)
|
||||
|
||||
ACL_EVENT_FDTABLE *fdp;
|
||||
|
||||
#define ACCEPT_ADDRESS_LENGTH ((sizeof(struct sockaddr_in) + 16))
|
||||
@ -73,20 +75,44 @@ static void stream_on_close(ACL_VSTREAM *stream, void *arg)
|
||||
}
|
||||
|
||||
/* 必须在释放 fdp->event_read/fdp->event_write 前关闭套接口句柄 */
|
||||
|
||||
if (ACL_VSTREAM_SOCK(stream) != ACL_SOCKET_INVALID && stream->close_fn)
|
||||
shutdown(ACL_VSTREAM_SOCK(stream), 0);
|
||||
shutdown(ACL_VSTREAM_SOCK(stream), 1);
|
||||
if (ACL_VSTREAM_SOCK(stream) != ACL_SOCKET_INVALID
|
||||
&& stream->close_fn)
|
||||
{
|
||||
(void) stream->close_fn(ACL_VSTREAM_SOCK(stream));
|
||||
else if (ACL_VSTREAM_FILE(stream) != ACL_FILE_INVALID && stream->fclose_fn)
|
||||
} else if (ACL_VSTREAM_FILE(stream) != ACL_FILE_INVALID
|
||||
&& stream->fclose_fn)
|
||||
{
|
||||
(void) stream->fclose_fn(ACL_VSTREAM_FILE(stream));
|
||||
}
|
||||
|
||||
ACL_VSTREAM_SOCK(stream) = ACL_SOCKET_INVALID;
|
||||
ACL_VSTREAM_FILE(stream) = ACL_FILE_INVALID;
|
||||
|
||||
if (fdp->event_read) {
|
||||
acl_myfree(fdp->event_read);
|
||||
/* 如果完成端口处于未决状态,则不能释放重叠结构,需在主循环的
|
||||
* GetQueuedCompletionStatus 调用后来释放
|
||||
*/
|
||||
if (HasOverlappedIoCompleted(&fdp->event_read->overlapped))
|
||||
acl_myfree(fdp->event_read);
|
||||
else {
|
||||
fdp->event_read->type = IOCP_EVENT_DEAD;
|
||||
fdp->event_read->fdp = NULL;
|
||||
}
|
||||
fdp->event_read = NULL;
|
||||
}
|
||||
if (fdp->event_write) {
|
||||
acl_myfree(fdp->event_write);
|
||||
/* 如果完成端口处于未决状态,则不能释放重叠结构,需在主循环的
|
||||
* GetQueuedCompletionStatus 调用后来释放
|
||||
*/
|
||||
if (HasOverlappedIoCompleted(&fdp->event_write->overlapped))
|
||||
acl_myfree(fdp->event_write);
|
||||
else {
|
||||
fdp->event_write->type = IOCP_EVENT_DEAD;
|
||||
fdp->event_write->fdp = NULL;
|
||||
}
|
||||
|
||||
fdp->event_write = NULL;
|
||||
}
|
||||
|
||||
@ -741,42 +767,64 @@ TAG_DONE:
|
||||
DWORD lastError = 0;
|
||||
IOCP_EVENT *iocp_event = NULL;
|
||||
|
||||
isSuccess = GetQueuedCompletionStatus(ev->h_iocp, &bytesTransferred,
|
||||
(DWORD*) &fdp, (OVERLAPPED**) &iocp_event, delay);
|
||||
isSuccess = GetQueuedCompletionStatus(ev->h_iocp,
|
||||
&bytesTransferred, (DWORD*) &fdp,
|
||||
(OVERLAPPED**) &iocp_event, delay);
|
||||
|
||||
if (!isSuccess) {
|
||||
if (iocp_event == NULL)
|
||||
break;
|
||||
if (!(fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT))) {
|
||||
if (iocp_event->type == IOCP_EVENT_DEAD)
|
||||
acl_myfree(iocp_event);
|
||||
else if (iocp_event->fdp == NULL) {
|
||||
acl_msg_warn("%s(%d): fdp null",
|
||||
myname, __LINE__);
|
||||
acl_myfree(iocp_event);
|
||||
} else if (iocp_event->fdp != fdp)
|
||||
acl_msg_fatal("%s(%d): invalid fdp",
|
||||
myname, __LINE__);
|
||||
else if (!(fdp->event_type & (ACL_EVENT_XCPT
|
||||
| ACL_EVENT_RW_TIMEOUT)))
|
||||
{
|
||||
fdp->event_type |= ACL_EVENT_XCPT;
|
||||
fdp->fdidx_ready = eventp->fdcnt_ready;
|
||||
eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp;
|
||||
eventp->fdtabs_ready[eventp->fdcnt_ready] = fdp;
|
||||
eventp->fdcnt_ready++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
acl_assert(fdp == iocp_event->fdp);
|
||||
|
||||
if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT)))
|
||||
if ((fdp->event_type & (ACL_EVENT_XCPT
|
||||
| ACL_EVENT_RW_TIMEOUT)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iocp_event->type == IOCP_EVENT_READ) {
|
||||
acl_assert(fdp->event_read == iocp_event);
|
||||
iocp_event->type &= ~IOCP_EVENT_READ;
|
||||
fdp->stream->sys_read_ready = 1;
|
||||
if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0)
|
||||
if ((fdp->event_type & (ACL_EVENT_READ
|
||||
| ACL_EVENT_WRITE)) == 0)
|
||||
{
|
||||
fdp->event_type |= ACL_EVENT_READ;
|
||||
fdp->fdidx_ready = eventp->fdcnt_ready;
|
||||
eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp;
|
||||
eventp->fdtabs_ready[eventp->fdcnt_ready] = fdp;
|
||||
eventp->fdcnt_ready++;
|
||||
}
|
||||
}
|
||||
if (iocp_event->type == IOCP_EVENT_WRITE) {
|
||||
acl_assert(fdp->event_write == iocp_event);
|
||||
iocp_event->type &= ~IOCP_EVENT_WRITE;
|
||||
if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0)
|
||||
if ((fdp->event_type & (ACL_EVENT_READ
|
||||
| ACL_EVENT_WRITE)) == 0)
|
||||
{
|
||||
fdp->event_type |= ACL_EVENT_WRITE;
|
||||
fdp->fdidx_ready = eventp->fdcnt_ready;
|
||||
eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp;
|
||||
eventp->fdtabs_ready[eventp->fdcnt_ready] = fdp;
|
||||
eventp->fdcnt_ready++;
|
||||
}
|
||||
}
|
||||
delay = 0;
|
||||
|
@ -481,10 +481,10 @@ static void handleClose(EVENT_WMSG *ev, ACL_SOCKET sockfd)
|
||||
return;
|
||||
else if (fdp->r_callback)
|
||||
fdp->r_callback(ACL_EVENT_XCPT, &ev->event,
|
||||
NULL, fdp->r_context);
|
||||
fdp->stream, fdp->r_context);
|
||||
else if (fdp->w_callback)
|
||||
fdp->w_callback(ACL_EVENT_XCPT, &ev->event,
|
||||
NULL, fdp->w_context);
|
||||
fdp->stream, fdp->w_context);
|
||||
/*
|
||||
else
|
||||
acl_msg_error("%s(%d): w_callback and r_callback null"
|
||||
@ -506,7 +506,7 @@ static void handleConnect(EVENT_WMSG *ev, ACL_SOCKET sockfd)
|
||||
else {
|
||||
fdp->stream->flag &= ~ACL_VSTREAM_FLAG_CONNECTING;
|
||||
fdp->w_callback(ACL_EVENT_WRITE, &ev->event,
|
||||
NULL, fdp->w_context);
|
||||
fdp->stream, fdp->w_context);
|
||||
}
|
||||
}
|
||||
|
||||
@ -520,7 +520,8 @@ static void handleAccept(EVENT_WMSG *ev, ACL_SOCKET sockfd)
|
||||
else if (fdp->r_callback == NULL)
|
||||
acl_msg_fatal("%s(%d): fdp callback null", myname, __LINE__);
|
||||
|
||||
fdp->r_callback(ACL_EVENT_READ, &ev->event, NULL, fdp->r_context);
|
||||
fdp->r_callback(ACL_EVENT_READ, &ev->event,
|
||||
fdp->stream, fdp->r_context);
|
||||
}
|
||||
|
||||
static void handleRead(EVENT_WMSG *ev, ACL_SOCKET sockfd)
|
||||
@ -532,15 +533,15 @@ static void handleRead(EVENT_WMSG *ev, ACL_SOCKET sockfd)
|
||||
acl_msg_error("%s(%d): fdp null for sockfd(%d)",
|
||||
myname, __LINE__, (int) sockfd);
|
||||
else if ((fdp->stream->type & ACL_VSTREAM_TYPE_LISTEN))
|
||||
fdp->r_callback(ACL_EVENT_READ, &ev->event, NULL,
|
||||
fdp->r_context);
|
||||
fdp->r_callback(ACL_EVENT_READ, &ev->event,
|
||||
fdp->stream, fdp->r_context);
|
||||
else if (fdp->r_callback != NULL) {
|
||||
/* 该描述字可读则设置 ACL_VSTREAM 的系统可读标志从而触发
|
||||
* ACL_VSTREAM 流在读时调用系统的 read 函数
|
||||
*/
|
||||
fdp->stream->sys_read_ready = 1;
|
||||
fdp->r_callback(ACL_EVENT_READ, &ev->event,
|
||||
NULL, fdp->r_context);
|
||||
fdp->stream, fdp->r_context);
|
||||
}
|
||||
/* else
|
||||
acl_msg_error("%s(%d): fdp->r_callback null for sockfd(%d)",
|
||||
@ -560,7 +561,7 @@ static void handleWrite(EVENT_WMSG *ev, ACL_SOCKET sockfd)
|
||||
handleConnect(ev, sockfd);
|
||||
else if (fdp->w_callback != NULL)
|
||||
fdp->w_callback(ACL_EVENT_WRITE, &ev->event,
|
||||
NULL, fdp->w_context);
|
||||
fdp->stream, fdp->w_context);
|
||||
/*
|
||||
else
|
||||
acl_msg_error("%s(%d): fdp->w_callback null for sockfd(%d)",
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
#include "init.h"
|
||||
|
||||
static char *version = "lib_acl_3.0.16";
|
||||
static char *version = "lib_acl_3.0.17";
|
||||
|
||||
const char *acl_version(void)
|
||||
{
|
||||
|
@ -83,7 +83,6 @@ struct acl_pthread_pool_t {
|
||||
thread_worker *thr_first; /* first idle thread */
|
||||
thread_worker *thr_iter; /* for bat operation */
|
||||
thread_cond *cond_first;
|
||||
thread_cond *cond_last;
|
||||
int poller_running; /* is poller thread running ? */
|
||||
int qlen; /* the work queue's length */
|
||||
int job_nslot;
|
||||
@ -193,7 +192,7 @@ static thread_cond *thread_cond_create(void)
|
||||
thread_cond *cond = (thread_cond*)
|
||||
acl_mycalloc(1, sizeof(thread_cond));
|
||||
|
||||
acl_pthread_cond_init(&cond->cond, NULL);
|
||||
acl_assert(acl_pthread_cond_init(&cond->cond, NULL) == 0);
|
||||
return cond;
|
||||
}
|
||||
|
||||
@ -207,7 +206,6 @@ static thread_worker *worker_create(acl_pthread_pool_t *thr_pool)
|
||||
{
|
||||
thread_worker *thr = (thread_worker*) acl_mycalloc(1,
|
||||
sizeof(thread_worker));
|
||||
thread_cond *cond = thr_pool->cond_first;
|
||||
|
||||
thr->id = (unsigned long) acl_pthread_self();
|
||||
thr->idle = thr_pool->idle_timeout;
|
||||
@ -222,27 +220,20 @@ static thread_worker *worker_create(acl_pthread_pool_t *thr_pool)
|
||||
} else
|
||||
thr->idle = 0;
|
||||
|
||||
if (cond == NULL) {
|
||||
cond = thread_cond_create();
|
||||
acl_assert(acl_pthread_cond_init(&cond->cond, NULL) == 0);
|
||||
} else {
|
||||
thr_pool->cond_first = cond->next;
|
||||
if (thr_pool->cond_last == cond)
|
||||
thr_pool->cond_last = NULL;
|
||||
}
|
||||
if (thr_pool->cond_first != NULL) {
|
||||
thr->cond = thr_pool->cond_first;
|
||||
thr_pool->cond_first = thr_pool->cond_first->next;
|
||||
} else
|
||||
thr->cond = thread_cond_create();
|
||||
|
||||
thr->cond = cond;
|
||||
thr->mutex = &thr_pool->worker_mutex;
|
||||
return thr;
|
||||
}
|
||||
|
||||
static void worker_free(acl_pthread_pool_t *thr_pool, thread_worker *thr)
|
||||
{
|
||||
if (thr_pool->cond_first == NULL)
|
||||
thr_pool->cond_first = thr->cond;
|
||||
else
|
||||
thr_pool->cond_last->next = thr->cond;
|
||||
thr_pool->cond_last = thr->cond;
|
||||
thr->cond->next = thr_pool->cond_first;
|
||||
thr_pool->cond_first = thr->cond;
|
||||
acl_myfree(thr);
|
||||
}
|
||||
|
||||
@ -431,19 +422,18 @@ static void *worker_thread(void* arg)
|
||||
}
|
||||
}
|
||||
|
||||
thr = worker_create(thr_pool);
|
||||
acl_assert(thr->mutex == &thr_pool->worker_mutex);
|
||||
mutex = thr->mutex;
|
||||
|
||||
/* lock the thread pool's global mutex at first */
|
||||
|
||||
status = acl_pthread_mutex_lock(mutex);
|
||||
status = acl_pthread_mutex_lock(&thr_pool->worker_mutex);
|
||||
if (status != 0) {
|
||||
SET_ERRNO(status);
|
||||
acl_msg_fatal("%s(%d), %s: lock failed: %s", __FILE__,
|
||||
__LINE__, myname, acl_last_serror());
|
||||
}
|
||||
|
||||
thr = worker_create(thr_pool);
|
||||
mutex = thr->mutex;
|
||||
|
||||
for (;;) {
|
||||
|
||||
/* handle thread self's job first */
|
||||
@ -498,7 +488,7 @@ static void *worker_thread(void* arg)
|
||||
status = acl_pthread_mutex_unlock(mutex);
|
||||
if (status != 0) {
|
||||
SET_ERRNO(status);
|
||||
acl_msg_error("%s, %s(%d): unlock error(%s)",
|
||||
acl_msg_fatal("%s, %s(%d): unlock error(%s)",
|
||||
__FILE__, myname, __LINE__, acl_last_serror());
|
||||
}
|
||||
|
||||
@ -943,7 +933,6 @@ static void thread_pool_init(acl_pthread_pool_t *thr_pool)
|
||||
thr_pool->schedule_warn = 100;
|
||||
thr_pool->schedule_wait = 100;
|
||||
thr_pool->cond_first = NULL;
|
||||
thr_pool->cond_last = NULL;
|
||||
}
|
||||
|
||||
/* create work queue */
|
||||
|
@ -195,8 +195,8 @@ public:
|
||||
*/
|
||||
bool timeout_callback()
|
||||
{
|
||||
std::cout << "Timeout ..." << std::endl;
|
||||
return (true);
|
||||
std::cout << "Timeout, delete it ..." << std::endl;
|
||||
return (false);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -239,7 +239,7 @@ public:
|
||||
client->add_timeout_callback(callback);
|
||||
|
||||
// 从异步流读一行数据
|
||||
client->gets(10, false);
|
||||
client->gets(3, false);
|
||||
return (true);
|
||||
}
|
||||
};
|
||||
@ -251,7 +251,7 @@ static void usage(const char* procname)
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
bool use_kernel = true;
|
||||
bool use_kernel = false;
|
||||
int ch;
|
||||
|
||||
while ((ch = getopt(argc, argv, "hk")) > 0)
|
||||
|
@ -194,6 +194,12 @@
|
||||
<Culture>0x0804</Culture>
|
||||
<AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>copy ..\..\..\dist\lib\win32\lib_acl_d.dll $(OutDir) /Y
|
||||
copy ..\..\..\dist\lib\win32\lib_acl_cpp_d.dll $(OutDir) /Y
|
||||
copy ..\..\..\dist\lib\win32\lib_protocol_d.dll $(OutDir) /Y
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Releasedll|Win32'">
|
||||
<ClCompile>
|
||||
@ -226,8 +232,10 @@
|
||||
<AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>
|
||||
</Command>
|
||||
<Command>copy ..\..\..\dist\lib\win32\lib_acl.dll $(OutDir) /Y
|
||||
copy ..\..\..\dist\lib\win32\lib_acl_cpp.dll $(OutDir) /Y
|
||||
copy ..\..\..\dist\lib\win32\lib_protocol.dll $(OutDir) /Y
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
2
samples/thread/thread_pool4/Makefile
Normal file
2
samples/thread/thread_pool4/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
include ../Makefile.in
|
||||
PROG = thread_pool_client
|
28
samples/thread/thread_pool4/main.c
Normal file
28
samples/thread/thread_pool4/main.c
Normal file
@ -0,0 +1,28 @@
|
||||
#include <getopt.h>
|
||||
#include "lib_acl.h"
|
||||
|
||||
static void thread_run(void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int nthreads = 200, count = 100, i;
|
||||
acl_pthread_pool_t *thrpool;
|
||||
|
||||
thrpool = acl_thread_pool_create(nthreads, 1);
|
||||
|
||||
for (i = 0; i < nthreads; i++)
|
||||
acl_pthread_pool_add(thrpool, thread_run, &count);
|
||||
|
||||
sleep(2);
|
||||
|
||||
for (i = 0; i < nthreads; i++)
|
||||
acl_pthread_pool_add(thrpool, thread_run, &count);
|
||||
|
||||
printf("enter any key to exit\r\n");
|
||||
getchar();
|
||||
acl_pthread_pool_destroy(thrpool);
|
||||
return 0;
|
||||
}
|
3
samples/thread/thread_pool4/valgrind.sh
Normal file
3
samples/thread/thread_pool4/valgrind.sh
Normal file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
valgrind --tool=memcheck --leak-check=yes -v ./thread_pool_client
|
Loading…
Reference in New Issue
Block a user