From: yue wang <nihaoaheheda@gmail.com>
To: emacs-devel@gnu.org
Subject: I broke through the limitation of only 32 child processes that can be created on windows emacs
Date: Sun, 16 Jun 2024 17:09:45 +0800 [thread overview]
Message-ID: <CAGSQiokHXZmn+oosV4d7b67gmTy3mb3=NHkw6x=4wb6CT2Ra2w@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 12822 bytes --]
the related discusstion is here
https://emacs-china.org/t/windows-emacs-2024-6-16/27392
I modified from github commit 08e38818f6ff4e514ac291bc5a7686f4390759b0 .
1 in build phase
add macro -DFD_SETSIZE=4096
2 modify w32.h and w32pro.h
git diff is below
diff --git a/src/w32.h b/src/w32.h
index cf470ae9901..0340f10e62b 100644
--- a/src/w32.h
+++ b/src/w32.h
@@ -29,7 +29,7 @@ along with GNU Emacs. If not, see <
https://www.gnu.org/licenses/>. */
/* File descriptor set emulation. */
/* MSVC runtime library has limit of 64 descriptors by default */
-#define FD_SETSIZE 64
+#define FD_SETSIZE 4096
typedef struct {
unsigned int bits[FD_SETSIZE / 32];
} fd_set;
diff --git a/src/w32proc.c b/src/w32proc.c
index 40181e09830..60918cb4a41 100644
--- a/src/w32proc.c
+++ b/src/w32proc.c
@@ -62,6 +62,215 @@ along with GNU Emacs. If not, see <
https://www.gnu.org/licenses/>. */
#include "syssignal.h"
#include "w32term.h"
#include "coding.h"
+#include <windows.h>
+
+#define MY_MAXIMUM_WAIT_OBJECTS 4096
+// 最大等待对象数,额外的一个用于线程退出event
+#define MY_MAX_WAIT_OBJECTS 63
+#define MY_WAIT_TIMEOUT 0x9999
+#define MY_WAIT_FAILED 0x9998
+#define MY_WAIT_ABANDONED_0 0x5000
+
+
+// 线程参数结构
+typedef struct {
+ HANDLE *handles;
+ int count;
+ BOOL bWaitAll;
+ DWORD dwMilliseconds;
+ HANDLE completionEvent; // 用于通知主线程该线程的WaitForMultipleObjects已完成
+ DWORD *threadResult; // 获取线程调用WaitForMultipleObjects的返回值
+ HANDLE exitEvent; // 用于控制线程退出
+} WaitForThreadData;
+
+// 线程函数,等待一组句柄
+DWORD WINAPI WaitForThreadProc(LPVOID lpParam) {
+ WaitForThreadData *params = (WaitForThreadData *)lpParam;
+ HANDLE *allHandles = (HANDLE *)malloc((params->count + 1) *
sizeof(HANDLE));
+ memcpy(allHandles, params->handles, params->count * sizeof(HANDLE));
+ allHandles[params->count] = params->exitEvent;
+
+ DWORD result = WaitForMultipleObjects(params->count + 1, allHandles,
params->bWaitAll, params->dwMilliseconds);
+ if (result == WAIT_OBJECT_0 + params->count) {
+ // exitEvent 被触发,线程退出
+ result = WAIT_TIMEOUT;
+ } else {
+ *params->threadResult = result;
+ }
+
+ // 通知主线程该组已完成
+ SetEvent(params->completionEvent);
+ free(allHandles);
+ return result;
+}
+// 扩展的 WaitForMultipleObjects 函数 ,注意返回值和原版不一样
+DWORD WaitForMultipleObjectsCustom(DWORD nCount, CONST HANDLE *lpHandles,
BOOL bWaitAll, DWORD dwMilliseconds) {
+ // emacs sys_select 中调用 WaitForMultipleObjects 时 bWaitAll 参数都为 FALSE
+ bWaitAll = FALSE;
+ if (nCount <= 64) {
+ // 句柄数未超过限制,直接调用 WaitForMultipleObjects
+ DWORD result = WaitForMultipleObjects(nCount, lpHandles, bWaitAll,
dwMilliseconds);
+ if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + nCount) {
+ return result - WAIT_OBJECT_0;
+ } else if (WAIT_TIMEOUT == result) {
+ return MY_WAIT_TIMEOUT;
+ } else if (result >= WAIT_ABANDONED_0 && result < WAIT_ABANDONED_0
+ nCount) {
+ return result - WAIT_ABANDONED_0 + MY_WAIT_ABANDONED_0;
+ } else {
+ return MY_WAIT_FAILED;
+ }
+ }
+
+ // 将句柄分组,每组最多 MY_MAX_WAIT_OBJECTS 个句柄
+ int numGroups = (nCount + MY_MAX_WAIT_OBJECTS - 1) /
MY_MAX_WAIT_OBJECTS;
+ HANDLE *groupCompletionEvents = (HANDLE *)malloc(numGroups *
sizeof(HANDLE));
+ WaitForThreadData *threadParams = (WaitForThreadData
*)malloc(numGroups * sizeof(WaitForThreadData));
+ HANDLE *threads = (HANDLE *)malloc(numGroups * sizeof(HANDLE));
+ DWORD *threadResults = (DWORD *)malloc(numGroups * sizeof(DWORD));
+ HANDLE *exitEvents = (HANDLE *)malloc(numGroups * sizeof(HANDLE)); //
用于控制线程退出
+ DWORD startTime = GetTickCount();
+ DWORD elapsedTime = 0;
+
+ for (int i = 0; i < numGroups; ++i) {
+ int groupCount = (i == numGroups - 1) ? (nCount - i *
MY_MAX_WAIT_OBJECTS) : MY_MAX_WAIT_OBJECTS;
+ threadParams[i].handles = (HANDLE *)(lpHandles + i *
MY_MAX_WAIT_OBJECTS);
+ threadParams[i].count = groupCount;
+ threadParams[i].bWaitAll = bWaitAll;
+ threadParams[i].dwMilliseconds = dwMilliseconds;
+ threadParams[i].completionEvent = CreateEvent(NULL, FALSE, FALSE,
NULL);
+ threadParams[i].threadResult = &threadResults[i];
+ threadParams[i].exitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ groupCompletionEvents[i] = threadParams[i].completionEvent;
+ exitEvents[i] = threadParams[i].exitEvent;
+
+ threads[i] = CreateThread(NULL, 0, WaitForThreadProc,
&threadParams[i], 0, NULL);
+ }
+
+ // 等待任一组完成
+ DWORD result;
+ if (dwMilliseconds != INFINITE) {
+ DWORD remainingTime = dwMilliseconds - elapsedTime;
+ result = WaitForMultipleObjects(numGroups, groupCompletionEvents,
bWaitAll, remainingTime);
+ } else {
+ result = WaitForMultipleObjects(numGroups, groupCompletionEvents,
bWaitAll, dwMilliseconds);
+ }
+
+ // 通知所有线程退出
+ for (int i = 0; i < numGroups; ++i) {
+ SetEvent(exitEvents[i]); // 新增
+ }
+
+ // 获取结果
+ if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + numGroups) {
+ DWORD inner_result = threadResults[result - WAIT_OBJECT_0];
+ if (inner_result >= WAIT_OBJECT_0 && inner_result < WAIT_OBJECT_0
+ threadParams[result - WAIT_OBJECT_0].count) {
+ result = inner_result + (result - WAIT_OBJECT_0) *
MY_MAX_WAIT_OBJECTS;
+ } else if (inner_result >= WAIT_ABANDONED_0 && inner_result <
WAIT_ABANDONED_0 + MY_MAX_WAIT_OBJECTS) {
+ result = inner_result - WAIT_ABANDONED_0 + MY_WAIT_ABANDONED_0;
+ } else if (WAIT_TIMEOUT == inner_result) {
+ result = MY_WAIT_TIMEOUT;
+ } else {
+ result = MY_WAIT_FAILED;
+ }
+ } else if (WAIT_TIMEOUT == result) {
+ result = MY_WAIT_TIMEOUT;
+ } else if (result >= WAIT_ABANDONED_0 && result < WAIT_ABANDONED_0 +
numGroups) {
+ result = result - WAIT_ABANDONED_0 + MY_WAIT_ABANDONED_0 ;
+ } else {
+ result = MY_WAIT_FAILED;
+ }
+
+ // 等待所有线程结束
+ WaitForMultipleObjects(numGroups, threads, TRUE, INFINITE);
+
+ // 关闭句柄和释放资源
+ for (int i = 0; i < numGroups; ++i) {
+ CloseHandle(threads[i]);
+ CloseHandle(groupCompletionEvents[i]);
+ CloseHandle(exitEvents[i]); // 新增
+ }
+
+ free(groupCompletionEvents);
+ free(threadParams);
+ free(threads);
+ free(threadResults);
+ free(exitEvents); // 新增
+
+ return result;
+}
+
+typedef struct {
+ DWORD nCount;
+ HANDLE* lpHandles;
+ BOOL bWaitAll;
+ DWORD dwMilliseconds;
+ HANDLE event;
+ HANDLE exitEvent;
+ DWORD threadResult;
+} MsgWaitThreadData;
+
+DWORD WINAPI MsgWaitThreadFunction(LPVOID param) {
+ MsgWaitThreadData* data = (MsgWaitThreadData*)param;
+ HANDLE *allHandles = (HANDLE *)malloc((data->nCount + 1) *
sizeof(HANDLE));
+ memcpy(allHandles, data->lpHandles, data->nCount * sizeof(HANDLE));
+ allHandles[data->nCount] = data->exitEvent;
+ DWORD result = WaitForMultipleObjectsCustom(data->nCount+1,
allHandles, data->bWaitAll, data->dwMilliseconds);
+ // printf("WaitForMultipleObjectsCustom result: %lu\n", result);
+ if (result == WAIT_OBJECT_0 + data->nCount) {
+ // exitEvent 被触发,线程退出
+ data->threadResult = MY_WAIT_FAILED;
+ } else {
+ data->threadResult = result;
+ }
+
+ // 通知主线程该组已完成
+ SetEvent(data->event);
+ free(allHandles);
+
+ return 0;
+}
+
+DWORD MsgWaitForMultipleObjectsCustom(DWORD nCount, HANDLE* lpHandles,
BOOL bWaitAll, DWORD dwMilliseconds, DWORD dwWakeMask) {
+ // emacs sys_select 中调用 MsgWaitForMultipleObjects 时 bWaitAll 参数都为 FALSE
+ bWaitAll = FALSE;
+ HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL); // completeEvent
+ if (event == NULL) {
+ return MY_WAIT_FAILED;
+ }
+ HANDLE exitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (event == NULL) {
+ return MY_WAIT_FAILED;
+ }
+
+ MsgWaitThreadData data = { nCount, lpHandles, bWaitAll,
dwMilliseconds, event, exitEvent, MY_WAIT_FAILED };
+ HANDLE thread = CreateThread(NULL, 0, MsgWaitThreadFunction, &data, 0,
NULL);
+ if (thread == NULL) {
+ CloseHandle(event);
+ return MY_WAIT_FAILED;
+ }
+
+ DWORD result = MsgWaitForMultipleObjects(1, &event, FALSE,
dwMilliseconds, dwWakeMask);
+ SetEvent(exitEvent);
+ // printf("MsgWaitForMultipleObjects result: %lu\n", result);
+ if (result == WAIT_OBJECT_0) {
+ result = data.threadResult;
+ } else if (result == WAIT_OBJECT_0 + 1) {
+ // 消息队列中有消息
+ result = WAIT_OBJECT_0 + nCount; // 表示消息队列有消息
+ } else if (result == WAIT_TIMEOUT) {
+ result = MY_WAIT_TIMEOUT;
+ } else {
+ result = MY_WAIT_FAILED; // 直接返回结果
+ }
+
+ WaitForSingleObject(thread, INFINITE);
+
+ CloseHandle(exitEvent);
+ CloseHandle(event);
+ CloseHandle(thread);
+ return result;
+}
+
void w32_raise (int);
@@ -1566,15 +1775,15 @@ waitpid (pid_t pid, int *status, int options)
quitting in that case. */
if (!dont_wait)
maybe_quit ();
- active = WaitForMultipleObjects (nh, wait_hnd, FALSE, timeout_ms);
- } while (active == WAIT_TIMEOUT && !dont_wait);
+ active = WaitForMultipleObjectsCustom (nh, wait_hnd, FALSE,
timeout_ms);
+ } while (active == MY_WAIT_TIMEOUT && !dont_wait);
- if (active == WAIT_FAILED)
+ if (active == MY_WAIT_FAILED)
{
errno = EBADF;
return -1;
}
- else if (active == WAIT_TIMEOUT && dont_wait)
+ else if (active == MY_WAIT_TIMEOUT && dont_wait)
{
/* PID specifies our subprocess, but it didn't exit yet, so its
status is not yet available. */
@@ -1584,14 +1793,14 @@ waitpid (pid_t pid, int *status, int options)
return 0;
}
else if (active >= WAIT_OBJECT_0
- && active < WAIT_OBJECT_0+MAXIMUM_WAIT_OBJECTS)
+ && active < WAIT_OBJECT_0+MY_MAXIMUM_WAIT_OBJECTS)
{
active -= WAIT_OBJECT_0;
}
- else if (active >= WAIT_ABANDONED_0
- && active < WAIT_ABANDONED_0+MAXIMUM_WAIT_OBJECTS)
+ else if (active >= MY_WAIT_ABANDONED_0
+ && active < MY_WAIT_ABANDONED_0+MY_MAXIMUM_WAIT_OBJECTS)
{
- active -= WAIT_ABANDONED_0;
+ active -= MY_WAIT_ABANDONED_0;
}
else
emacs_abort ();
@@ -2500,13 +2709,15 @@ sys_select (int nfds, SELECT_TYPE *rfds,
SELECT_TYPE *wfds, SELECT_TYPE *efds,
/* Wait for input or child death to be signaled. If user input is
allowed, then also accept window messages. */
- if (FD_ISSET (0, &orfds))
- active = MsgWaitForMultipleObjects (nh + nc, wait_hnd, FALSE,
timeout_ms,
- QS_ALLINPUT);
+ if (FD_ISSET (0, &orfds)){
+ active = MsgWaitForMultipleObjectsCustom (nh + nc, wait_hnd, FALSE,
timeout_ms,
+ QS_ALLINPUT);
+ }
+
else
- active = WaitForMultipleObjects (nh + nc, wait_hnd, FALSE, timeout_ms);
+ active = WaitForMultipleObjectsCustom (nh + nc, wait_hnd, FALSE,
timeout_ms);
- if (active == WAIT_FAILED)
+ if (active == MY_WAIT_FAILED)
{
DebPrint (("select.WaitForMultipleObjects (%d, %lu) failed with
%lu\n",
nh + nc, timeout_ms, GetLastError ()));
@@ -2517,7 +2728,7 @@ sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE
*wfds, SELECT_TYPE *efds,
errno = EINTR;
return -1;
}
- else if (active == WAIT_TIMEOUT)
+ else if (active == MY_WAIT_TIMEOUT)
{
if (noninteractive)
{
@@ -2527,14 +2738,14 @@ sys_select (int nfds, SELECT_TYPE *rfds,
SELECT_TYPE *wfds, SELECT_TYPE *efds,
return 0;
}
else if (active >= WAIT_OBJECT_0
- && active < WAIT_OBJECT_0+MAXIMUM_WAIT_OBJECTS)
+ && active < WAIT_OBJECT_0+MY_MAXIMUM_WAIT_OBJECTS)
{
active -= WAIT_OBJECT_0;
}
- else if (active >= WAIT_ABANDONED_0
- && active < WAIT_ABANDONED_0+MAXIMUM_WAIT_OBJECTS)
+ else if (active >= MY_WAIT_ABANDONED_0
+ && active < MY_WAIT_ABANDONED_0+MY_MAXIMUM_WAIT_OBJECTS)
{
- active -= WAIT_ABANDONED_0;
+ active -= MY_WAIT_ABANDONED_0;
}
else
emacs_abort ();
[-- Attachment #2: Type: text/html, Size: 14733 bytes --]
reply other threads:[~2024-06-16 9:09 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAGSQiokHXZmn+oosV4d7b67gmTy3mb3=NHkw6x=4wb6CT2Ra2w@mail.gmail.com' \
--to=nihaoaheheda@gmail.com \
--cc=emacs-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).