diff --git a/Makefile b/Makefile index 628a34438..e4983c62e 100644 --- a/Makefile +++ b/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") diff --git a/changes.txt b/changes.txt index fe236aabf..ebc3b1687 100644 --- a/changes.txt +++ b/changes.txt @@ -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 diff --git a/lib_acl/changes.txt b/lib_acl/changes.txt index 7a7f9540c..9ac28d234 100644 --- a/lib_acl/changes.txt +++ b/lib_acl/changes.txt @@ -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 diff --git a/lib_acl/lib_acl.rc b/lib_acl/lib_acl.rc index b7e7b02e4..b0ec001d5 100644 --- a/lib_acl/lib_acl.rc +++ b/lib_acl/lib_acl.rc @@ -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" diff --git a/lib_acl/src/event/events_iocp.c b/lib_acl/src/event/events_iocp.c index d075fad72..e21cf85fb 100644 --- a/lib_acl/src/event/events_iocp.c +++ b/lib_acl/src/event/events_iocp.c @@ -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; diff --git a/lib_acl/src/event/events_wmsg.c b/lib_acl/src/event/events_wmsg.c index 2b5f2c202..9e06b542f 100644 --- a/lib_acl/src/event/events_wmsg.c +++ b/lib_acl/src/event/events_wmsg.c @@ -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)", diff --git a/lib_acl/src/init/acl_init.c b/lib_acl/src/init/acl_init.c index cc9c95648..070f48cdb 100644 --- a/lib_acl/src/init/acl_init.c +++ b/lib_acl/src/init/acl_init.c @@ -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) { diff --git a/lib_acl/src/thread/acl_pthread_pool.c b/lib_acl/src/thread/acl_pthread_pool.c index e02f02254..148377e17 100644 --- a/lib_acl/src/thread/acl_pthread_pool.c +++ b/lib_acl/src/thread/acl_pthread_pool.c @@ -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 */ diff --git a/lib_acl_cpp/samples/aio/aio_server/main.cpp b/lib_acl_cpp/samples/aio/aio_server/main.cpp index 437f0972b..6d23b4163 100644 --- a/lib_acl_cpp/samples/aio/aio_server/main.cpp +++ b/lib_acl_cpp/samples/aio/aio_server/main.cpp @@ -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) diff --git a/lib_acl_cpp/samples/winaio/winaio_vc2012.vcxproj b/lib_acl_cpp/samples/winaio/winaio_vc2012.vcxproj index 89f26452a..438a3bb85 100644 --- a/lib_acl_cpp/samples/winaio/winaio_vc2012.vcxproj +++ b/lib_acl_cpp/samples/winaio/winaio_vc2012.vcxproj @@ -194,6 +194,12 @@ 0x0804 $(IntDir);%(AdditionalIncludeDirectories) + + 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 + + @@ -226,8 +232,10 @@ $(IntDir);%(AdditionalIncludeDirectories) - - + 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 + diff --git a/samples/thread/thread_pool4/Makefile b/samples/thread/thread_pool4/Makefile new file mode 100644 index 000000000..36a1e0b2e --- /dev/null +++ b/samples/thread/thread_pool4/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = thread_pool_client diff --git a/samples/thread/thread_pool4/main.c b/samples/thread/thread_pool4/main.c new file mode 100644 index 000000000..2a749b52a --- /dev/null +++ b/samples/thread/thread_pool4/main.c @@ -0,0 +1,28 @@ +#include +#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; +} diff --git a/samples/thread/thread_pool4/valgrind.sh b/samples/thread/thread_pool4/valgrind.sh new file mode 100644 index 000000000..aad8796fe --- /dev/null +++ b/samples/thread/thread_pool4/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./thread_pool_client