ruby-changes:67601
From: Andrew <ko1@a...>
Date: Sun, 5 Sep 2021 11:42:30 +0900 (JST)
Subject: [ruby-changes:67601] 261a0e0e4a (ruby_3_0): Backport mutexes for socket and connection lists on win32 #4212 (#4218)
https://git.ruby-lang.org/ruby.git/commit/?id=261a0e0e4a From 261a0e0e4a3202ca004eddc3cc2cefc9e8d0a90a Mon Sep 17 00:00:00 2001 From: Andrew Aladjev <aladjev.andrew@g...> Date: Sun, 5 Sep 2021 05:42:08 +0300 Subject: Backport mutexes for socket and connection lists on win32 #4212 (#4218) Co-authored-by: nagachika <nagachika@r...> --- test/socket/test_tcp.rb | 25 ++++++++++ version.h | 6 +-- win32/win32.c | 120 ++++++++++++++++++++++++++++++++---------------- 3 files changed, 108 insertions(+), 43 deletions(-) diff --git a/test/socket/test_tcp.rb b/test/socket/test_tcp.rb index a9e2a41..b897ff5 100644 --- a/test/socket/test_tcp.rb +++ b/test/socket/test_tcp.rb @@ -115,4 +115,29 @@ class TestSocket_TCPSocket < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/socket/test_tcp.rb#L115 assert_raise(IO::WaitReadable) { svr.accept_nonblock(exception: true) } } end + + def test_accept_multithread + attempts_count = 5 + server_threads_count = 3 + client_threads_count = 3 + + attempts_count.times do + server_threads = Array.new(server_threads_count) do + Thread.new do + TCPServer.open("localhost", 0) do |server| + accept_threads = Array.new(client_threads_count) do + Thread.new { server.accept.close } + end + client_threads = Array.new(client_threads_count) do + Thread.new { TCPSocket.open(server.addr[3], server.addr[1]) } + end + client_threads.each(&:join) + accept_threads.each(&:join) + end + end + end + + server_threads.each(&:join) + end + end end if defined?(TCPSocket) diff --git a/version.h b/version.h index 8ba96bd..b7207ac 100644 --- a/version.h +++ b/version.h @@ -12,11 +12,11 @@ https://github.com/ruby/ruby/blob/trunk/version.h#L12 # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 3 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 125 +#define RUBY_PATCHLEVEL 126 #define RUBY_RELEASE_YEAR 2021 -#define RUBY_RELEASE_MONTH 8 -#define RUBY_RELEASE_DAY 29 +#define RUBY_RELEASE_MONTH 9 +#define RUBY_RELEASE_DAY 5 #include "ruby/version.h" diff --git a/win32/win32.c b/win32/win32.c index 82d9f1d..cad2784 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -696,9 +696,14 @@ rtc_error_handler(int e, const char *src, int line, const char *exe, const char https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L696 #endif static CRITICAL_SECTION select_mutex; + +static CRITICAL_SECTION socklist_mutex; static st_table *socklist = NULL; + +static CRITICAL_SECTION conlist_mutex; static st_table *conlist = NULL; #define conlist_disabled ((st_table *)-1) + static char *uenvarea; /* License: Ruby's */ @@ -723,11 +728,13 @@ free_conlist(st_data_t key, st_data_t val, st_data_t arg) https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L728 static void constat_delete(HANDLE h) { + EnterCriticalSection(&conlist_mutex); if (conlist && conlist != conlist_disabled) { st_data_t key = (st_data_t)h, val; st_delete(conlist, &key, &val); xfree((struct constat *)val); } + LeaveCriticalSection(&conlist_mutex); } /* License: Ruby's */ @@ -736,6 +743,8 @@ exit_handler(void) https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L743 { WSACleanup(); DeleteCriticalSection(&select_mutex); + DeleteCriticalSection(&socklist_mutex); + DeleteCriticalSection(&conlist_mutex); if (uenvarea) { free(uenvarea); uenvarea = NULL; @@ -746,15 +755,20 @@ exit_handler(void) https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L755 static void vm_exit_handler(ruby_vm_t *vm) { + EnterCriticalSection(&socklist_mutex); if (socklist) { st_free_table(socklist); socklist = NULL; } + LeaveCriticalSection(&socklist_mutex); + + EnterCriticalSection(&conlist_mutex); if (conlist && conlist != conlist_disabled) { st_foreach(conlist, free_conlist, 0); st_free_table(conlist); conlist = NULL; } + LeaveCriticalSection(&conlist_mutex); } /* License: Ruby's */ @@ -787,6 +801,8 @@ StartSockets(void) https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L801 rb_fatal("could not find version 2 of winsock dll"); InitializeCriticalSection(&select_mutex); + InitializeCriticalSection(&socklist_mutex); + InitializeCriticalSection(&conlist_mutex); atexit(exit_handler); } @@ -799,11 +815,17 @@ StartSockets(void) https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L815 static inline int socklist_insert(SOCKET sock, int flag) { + int ret; + + EnterCriticalSection(&socklist_mutex); if (!socklist) { socklist = st_init_numtable(); install_vm_exit_handler(); } - return st_insert(socklist, (st_data_t)sock, (st_data_t)flag); + ret = st_insert(socklist, (st_data_t)sock, (st_data_t)flag); + LeaveCriticalSection(&socklist_mutex); + + return ret; } /* License: Ruby's */ @@ -813,11 +835,15 @@ socklist_lookup(SOCKET sock, int *flagp) https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L835 st_data_t data; int ret; - if (!socklist) - return 0; - ret = st_lookup(socklist, (st_data_t)sock, (st_data_t *)&data); - if (ret && flagp) - *flagp = (int)data; + EnterCriticalSection(&socklist_mutex); + if (socklist) { + ret = st_lookup(socklist, (st_data_t)sock, (st_data_t *)&data); + if (ret && flagp) + *flagp = (int)data; + } else { + ret = 0; + } + LeaveCriticalSection(&socklist_mutex); return ret; } @@ -830,17 +856,21 @@ socklist_delete(SOCKET *sockp, int *flagp) https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L856 st_data_t data; int ret; - if (!socklist) - return 0; - key = (st_data_t)*sockp; - if (flagp) - data = (st_data_t)*flagp; - ret = st_delete(socklist, &key, &data); - if (ret) { - *sockp = (SOCKET)key; + EnterCriticalSection(&socklist_mutex); + if (socklist) { + key = (st_data_t)*sockp; if (flagp) - *flagp = (int)data; + data = (st_data_t)*flagp; + ret = st_delete(socklist, &key, &data); + if (ret) { + *sockp = (SOCKET)key; + if (flagp) + *flagp = (int)data; + } + } else { + ret = 0; } + LeaveCriticalSection(&socklist_mutex); return ret; } @@ -6555,32 +6585,36 @@ constat_handle(HANDLE h) https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L6585 { st_data_t data; struct constat *p; + + EnterCriticalSection(&conlist_mutex); if (!conlist) { if (console_emulator_p()) { conlist = conlist_disabled; - return NULL; - } - conlist = st_init_numtable(); - install_vm_exit_handler(); - } - else if (conlist == conlist_disabled) { - return NULL; - } - if (st_lookup(conlist, (st_data_t)h, &data)) { - p = (struct constat *)data; - } - else { - CONSOLE_SCREEN_BUFFER_INFO csbi; - p = ALLOC(struct constat); - p->vt100.state = constat_init; - p->vt100.attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; - p->vt100.reverse = 0; - p->vt100.saved.X = p->vt100.saved.Y = 0; - if (GetConsoleScreenBufferInfo(h, &csbi)) { - p->vt100.attr = csbi.wAttributes; + } else { + conlist = st_init_numtable(); + install_vm_exit_handler(); + } + } + if (conlist != conlist_disabled) { + if (st_lookup(conlist, (st_data_t)h, &data)) { + p = (struct constat *)data; + } else { + CONSOLE_SCREEN_BUFFER_INFO csbi; + p = ALLOC(struct constat); + p->vt100.state = constat_init; + p->vt100.attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; + p->vt100.reverse = 0; + p->vt100.saved.X = p->vt100.saved.Y = 0; + if (GetConsoleScreenBufferInfo(h, &csbi)) { + p->vt100.attr = csbi.wAttributes; + } + st_insert(conlist, (st_data_t)h, (st_data_t)p); } - st_insert(conlist, (st_data_t)h, (st_data_t)p); + } else { + p = NULL; } + LeaveCriticalSection(&conlist_mutex); + return p; } @@ -6590,10 +6624,16 @@ constat_reset(HANDLE h) https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L6624 { st_data_t data; struct constat *p; - if (!conlist || conlist == conlist_disabled) return; - if (!st_lookup(conlist, (st_data_t)h, &data)) return; - p = (struct constat *)data; - p->vt100.state = constat_init; + + EnterCriticalSection(&conlist_mutex); + if ( + conlist && conlist != conlist_disabled && + st_lookup(conlist, (st_data_t)h, &data) + ) { + p = (struct constat *)data; + p->vt100.state = constat_init; + } + LeaveCriticalSection(&conlist_mutex); } #define FOREGROUND_MASK (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY) -- cgit v1.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/