Project

General

Profile

Bug #17394 » 4220.patch

Backport mutexes for socket and connection lists on win32 - puchuu (Andrew Aladjev), 02/23/2021 10:49 PM

View differences:

test/socket/test_tcp.rb
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)
version.h
#define RUBY_VERSION "2.6.7"
#define RUBY_RELEASE_DATE "2021-01-31"
#define RUBY_PATCHLEVEL 153
#define RUBY_PATCHLEVEL 154
#define RUBY_RELEASE_YEAR 2021
#define RUBY_RELEASE_MONTH 1
#define RUBY_RELEASE_DAY 31
#define RUBY_RELEASE_MONTH 2
#define RUBY_RELEASE_DAY 23
#include "ruby/version.h"
win32/win32.c
static CRITICAL_SECTION select_mutex;
#define NtSocketsInitialized 1
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 */
......
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 */
......
WSACleanup();
DeleteCriticalSection(&select_mutex);
}
DeleteCriticalSection(&socklist_mutex);
DeleteCriticalSection(&conlist_mutex);
if (uenvarea) {
free(uenvarea);
uenvarea = NULL;
......
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 */
......
rb_fatal("could not find version 2 of winsock dll");
InitializeCriticalSection(&select_mutex);
InitializeCriticalSection(&socklist_mutex);
InitializeCriticalSection(&conlist_mutex);
atexit(exit_handler);
}
......
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 */
......
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;
}
......
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;
}
......
{
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;
}
......
{
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)
(2-2/2)