diff options
Diffstat (limited to 'ext/socket/raddrinfo.c')
| -rw-r--r-- | ext/socket/raddrinfo.c | 299 |
1 files changed, 245 insertions, 54 deletions
diff --git a/ext/socket/raddrinfo.c b/ext/socket/raddrinfo.c index e79bcfa332..f1fbcc35de 100644 --- a/ext/socket/raddrinfo.c +++ b/ext/socket/raddrinfo.c @@ -277,8 +277,9 @@ numeric_getaddrinfo(const char *node, const char *service, void rb_freeaddrinfo(struct rb_addrinfo *ai) { - if (!ai->allocated_by_malloc) - freeaddrinfo(ai->ai); + if (!ai->allocated_by_malloc) { + if (ai->ai) freeaddrinfo(ai->ai); + } else { struct addrinfo *ai1, *ai2; ai1 = ai->ai; @@ -292,10 +293,22 @@ rb_freeaddrinfo(struct rb_addrinfo *ai) xfree(ai); } +static int +rsock_value_timeout_to_msec(VALUE timeout) +{ + double seconds = NUM2DBL(timeout); + if (seconds < 0) rb_raise(rb_eArgError, "timeout must not be negative"); + + double msec = seconds * 1000.0; + if (msec > UINT_MAX) rb_raise(rb_eArgError, "timeout too large"); + + return (unsigned int)(msec + 0.5); +} + #if GETADDRINFO_IMPL == 0 static int -rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai) +rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int _timeout) { return getaddrinfo(hostp, portp, hints, ai); } @@ -326,8 +339,14 @@ nogvl_getaddrinfo(void *arg) return (void *)(VALUE)ret; } +static void * +fork_safe_getaddrinfo(void *arg) +{ + return rb_thread_prevent_fork(nogvl_getaddrinfo, arg); +} + static int -rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai) +rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int _timeout) { struct getaddrinfo_arg arg; MEMZERO(&arg, struct getaddrinfo_arg, 1); @@ -335,7 +354,7 @@ rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hint arg.service = portp; arg.hints = hints; arg.res = ai; - return (int)(VALUE)rb_thread_call_without_gvl(nogvl_getaddrinfo, &arg, RUBY_UBF_IO, 0); + return (int)(VALUE)rb_thread_call_without_gvl(fork_safe_getaddrinfo, &arg, RUBY_UBF_IO, 0); } #elif GETADDRINFO_IMPL == 2 @@ -345,13 +364,14 @@ struct getaddrinfo_arg char *node, *service; struct addrinfo hints; struct addrinfo *ai; - int err, gai_errno, refcount, done, cancelled; + int err, gai_errno, refcount, done, cancelled, timedout; rb_nativethread_lock_t lock; rb_nativethread_cond_t cond; + int timeout; }; static struct getaddrinfo_arg * -allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addrinfo *hints) +allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addrinfo *hints, int timeout) { size_t hostp_offset = sizeof(struct getaddrinfo_arg); size_t portp_offset = hostp_offset + (hostp ? strlen(hostp) + 1 : 0); @@ -367,7 +387,7 @@ allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addr if (hostp) { arg->node = buf + hostp_offset; - strcpy(arg->node, hostp); + memcpy(arg->node, hostp, portp_offset - hostp_offset); } else { arg->node = NULL; @@ -375,7 +395,7 @@ allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addr if (portp) { arg->service = buf + portp_offset; - strcpy(arg->service, portp); + memcpy(arg->service, portp, bufsize - portp_offset); } else { arg->service = NULL; @@ -385,7 +405,8 @@ allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addr arg->ai = NULL; arg->refcount = 2; - arg->done = arg->cancelled = 0; + arg->done = arg->cancelled = arg->timedout = 0; + arg->timeout = timeout; rb_nativethread_lock_initialize(&arg->lock); rb_native_cond_initialize(&arg->cond); @@ -423,7 +444,7 @@ do_getaddrinfo(void *ptr) arg->err = err; arg->gai_errno = gai_errno; if (arg->cancelled) { - freeaddrinfo(arg->ai); + if (arg->ai) freeaddrinfo(arg->ai); } else { arg->done = 1; @@ -444,7 +465,19 @@ wait_getaddrinfo(void *ptr) struct getaddrinfo_arg *arg = (struct getaddrinfo_arg *)ptr; rb_nativethread_lock_lock(&arg->lock); while (!arg->done && !arg->cancelled) { - rb_native_cond_wait(&arg->cond, &arg->lock); + long msec = arg->timeout; + if (msec == 0) { + arg->cancelled = 1; + arg->timedout = 1; + } else if (msec > 0) { + rb_native_cond_timedwait(&arg->cond, &arg->lock, msec); + if (!arg->done) { + arg->cancelled = 1; + arg->timedout = 1; + } + } else { + rb_native_cond_wait(&arg->cond, &arg->lock); + } } rb_nativethread_lock_unlock(&arg->lock); return 0; @@ -462,41 +495,84 @@ cancel_getaddrinfo(void *ptr) rb_nativethread_lock_unlock(&arg->lock); } -static int -do_pthread_create(pthread_t *th, void *(*start_routine) (void *), void *arg) +int +raddrinfo_pthread_create(pthread_t *th, void *(*start_routine) (void *), void *arg) { int limit = 3, ret; + int saved_errno; +#ifdef HAVE_PTHREAD_ATTR_SETDETACHSTATE + pthread_attr_t attr; + pthread_attr_t *attr_p = &attr; + int err; + int init_retries = 0; + int init_retries_max = 3; +retry_attr_init: + if ((err = pthread_attr_init(attr_p)) != 0) { + if (err == ENOMEM && init_retries < init_retries_max) { + init_retries++; + rb_gc(); + goto retry_attr_init; + } + return err; + } + if ((err = pthread_attr_setdetachstate(attr_p, PTHREAD_CREATE_DETACHED)) != 0) { + saved_errno = errno; + pthread_attr_destroy(attr_p); + errno = saved_errno; + return err; // EINVAL - shouldn't happen + } +#else + pthread_attr_t *attr_p = NULL; +#endif do { // It is said that pthread_create may fail spuriously, so we follow the JDK and retry several times. // // https://bugs.openjdk.org/browse/JDK-8268605 // https://github.com/openjdk/jdk/commit/e35005d5ce383ddd108096a3079b17cb0bcf76f1 - ret = pthread_create(th, 0, start_routine, arg); + ret = pthread_create(th, attr_p, start_routine, arg); } while (ret == EAGAIN && limit-- > 0); +#ifdef HAVE_PTHREAD_ATTR_SETDETACHSTATE + saved_errno = errno; + pthread_attr_destroy(attr_p); + if (ret != 0) { + errno = saved_errno; + } +#else + if (ret == 0) { + pthread_detach(th); // this can race with shutdown routine of thread in some glibc versions + } +#endif return ret; } +static void * +fork_safe_do_getaddrinfo(void *ptr) +{ + return rb_thread_prevent_fork(do_getaddrinfo, ptr); +} + static int -rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai) +rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int timeout) { int retry; struct getaddrinfo_arg *arg; - int err, gai_errno = 0; + int err = 0, gai_errno = 0, timedout = 0; start: retry = 0; - arg = allocate_getaddrinfo_arg(hostp, portp, hints); + arg = allocate_getaddrinfo_arg(hostp, portp, hints, timeout); if (!arg) { return EAI_MEMORY; } pthread_t th; - if (do_pthread_create(&th, do_getaddrinfo, arg) != 0) { + if (raddrinfo_pthread_create(&th, fork_safe_do_getaddrinfo, arg) != 0) { + int err = errno; free_getaddrinfo_arg(arg); - return EAI_AGAIN; + errno = err; + return EAI_SYSTEM; } - pthread_detach(th); rb_thread_call_without_gvl2(wait_getaddrinfo, arg, cancel_getaddrinfo, arg); @@ -509,7 +585,8 @@ start: if (err == 0) *ai = arg->ai; } else if (arg->cancelled) { - err = EAI_AGAIN; + retry = 1; + timedout = arg->timedout; } else { // If already interrupted, rb_thread_call_without_gvl2 may return without calling wait_getaddrinfo. @@ -523,6 +600,12 @@ start: if (need_free) free_getaddrinfo_arg(arg); + if (timedout) { + VALUE host = rb_str_new_cstr(hostp); + VALUE port = rb_str_new_cstr(portp); + rsock_raise_user_specified_timeout(NULL, host, port); + } + // If the current thread is interrupted by asynchronous exception, the following raises the exception. // But if the current thread is interrupted by timer thread, the following returns; we need to manually retry. rb_thread_check_ints(); @@ -537,6 +620,10 @@ start: #endif +#define GETNAMEINFO_WONT_BLOCK(host, serv, flags) \ + ((!(host) || ((flags) & NI_NUMERICHOST)) && \ + (!(serv) || ((flags) & NI_NUMERICSERV))) + #if GETADDRINFO_IMPL == 0 int @@ -544,7 +631,7 @@ rb_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) { - return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); + return getnameinfo(sa, salen, host, (socklen_t)hostlen, serv, (socklen_t)servlen, flags); } #elif GETADDRINFO_IMPL == 1 @@ -574,6 +661,10 @@ rb_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) { + if (GETNAMEINFO_WONT_BLOCK(host, serv, flags)) { + return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); + } + struct getnameinfo_arg arg; int ret; arg.sa = sa; @@ -700,7 +791,11 @@ rb_getnameinfo(const struct sockaddr *sa, socklen_t salen, { int retry; struct getnameinfo_arg *arg; - int err, gni_errno = 0; + int err = 0, gni_errno = 0; + + if (GETNAMEINFO_WONT_BLOCK(host, serv, flags)) { + return getnameinfo(sa, salen, host, (socklen_t)hostlen, serv, (socklen_t)servlen, flags); + } start: retry = 0; @@ -711,11 +806,12 @@ start: } pthread_t th; - if (do_pthread_create(&th, do_getnameinfo, arg) != 0) { + if (raddrinfo_pthread_create(&th, do_getnameinfo, arg) != 0) { + int err = errno; free_getnameinfo_arg(arg); - return EAI_AGAIN; + errno = err; + return EAI_SYSTEM; } - pthread_detach(th); rb_thread_call_without_gvl2(wait_getnameinfo, arg, cancel_getnameinfo, arg); @@ -730,7 +826,7 @@ start: } } else if (arg->cancelled) { - err = EAI_AGAIN; + retry = 1; } else { // If already interrupted, rb_thread_call_without_gvl2 may return without calling wait_getnameinfo. @@ -805,8 +901,8 @@ str_is_number(const char *p) ((ptr)[0] == name[0] && \ rb_strlen_lit(name) == (len) && memcmp(ptr, name, len) == 0) -static char* -host_str(VALUE host, char *hbuf, size_t hbuflen, int *flags_ptr) +char* +raddrinfo_host_str(VALUE host, char *hbuf, size_t hbuflen, int *flags_ptr) { if (NIL_P(host)) { return NULL; @@ -844,8 +940,8 @@ host_str(VALUE host, char *hbuf, size_t hbuflen, int *flags_ptr) } } -static char* -port_str(VALUE port, char *pbuf, size_t pbuflen, int *flags_ptr) +char* +raddrinfo_port_str(VALUE port, char *pbuf, size_t pbuflen, int *flags_ptr) { if (NIL_P(port)) { return 0; @@ -897,7 +993,7 @@ rb_scheduler_getaddrinfo(VALUE scheduler, VALUE host, const char *service, for(i=0; i<len; i++) { ip_address = rb_ary_entry(ip_addresses_array, i); - hostp = host_str(ip_address, _hbuf, sizeof(_hbuf), &_additional_flags); + hostp = raddrinfo_host_str(ip_address, _hbuf, sizeof(_hbuf), &_additional_flags); error = numeric_getaddrinfo(hostp, service, hints, &ai); if (error == 0) { if (!res_allocated) { @@ -924,7 +1020,7 @@ rb_scheduler_getaddrinfo(VALUE scheduler, VALUE host, const char *service, } struct rb_addrinfo* -rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack) +rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack, VALUE timeout) { struct rb_addrinfo* res = NULL; struct addrinfo *ai; @@ -933,8 +1029,8 @@ rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_h char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; int additional_flags = 0; - hostp = host_str(host, hbuf, sizeof(hbuf), &additional_flags); - portp = port_str(port, pbuf, sizeof(pbuf), &additional_flags); + hostp = raddrinfo_host_str(host, hbuf, sizeof(hbuf), &additional_flags); + portp = raddrinfo_port_str(port, pbuf, sizeof(pbuf), &additional_flags); if (socktype_hack && hints->ai_socktype == 0 && str_is_number(portp)) { hints->ai_socktype = SOCK_DGRAM; @@ -959,7 +1055,8 @@ rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_h } if (!resolved) { - error = rb_getaddrinfo(hostp, portp, hints, &ai); + int t = NIL_P(timeout) ? -1 : rsock_value_timeout_to_msec(timeout); + error = rb_getaddrinfo(hostp, portp, hints, &ai, t); if (error == 0) { res = (struct rb_addrinfo *)xmalloc(sizeof(struct rb_addrinfo)); res->allocated_by_malloc = 0; @@ -992,7 +1089,7 @@ rsock_fd_family(int fd) } struct rb_addrinfo* -rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags) +rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags, VALUE timeout) { struct addrinfo hints; @@ -1000,7 +1097,7 @@ rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags) hints.ai_family = family; hints.ai_socktype = socktype; hints.ai_flags = flags; - return rsock_getaddrinfo(host, port, &hints, 1); + return rsock_getaddrinfo(host, port, &hints, 1, timeout); } VALUE @@ -1120,7 +1217,7 @@ make_hostent_internal(VALUE v) hostp = addr->ai_canonname; } else { - hostp = host_str(host, hbuf, sizeof(hbuf), NULL); + hostp = raddrinfo_host_str(host, hbuf, sizeof(hbuf), NULL); } rb_ary_push(ary, rb_str_new2(hostp)); @@ -1194,6 +1291,7 @@ addrinfo_memsize(const void *ptr) static const rb_data_type_t addrinfo_type = { "socket/addrinfo", {addrinfo_mark, addrinfo_free, addrinfo_memsize,}, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_WB_PROTECTED, }; static VALUE @@ -1231,7 +1329,7 @@ alloc_addrinfo(void) } static void -init_addrinfo(rb_addrinfo_t *rai, struct sockaddr *sa, socklen_t len, +init_addrinfo(VALUE self, rb_addrinfo_t *rai, struct sockaddr *sa, socklen_t len, int pfamily, int socktype, int protocol, VALUE canonname, VALUE inspectname) { @@ -1243,8 +1341,8 @@ init_addrinfo(rb_addrinfo_t *rai, struct sockaddr *sa, socklen_t len, rai->pfamily = pfamily; rai->socktype = socktype; rai->protocol = protocol; - rai->canonname = canonname; - rai->inspectname = inspectname; + RB_OBJ_WRITE(self, &rai->canonname, canonname); + RB_OBJ_WRITE(self, &rai->inspectname, inspectname); } VALUE @@ -1257,7 +1355,7 @@ rsock_addrinfo_new(struct sockaddr *addr, socklen_t len, a = addrinfo_s_allocate(rb_cAddrinfo); DATA_PTR(a) = rai = alloc_addrinfo(); - init_addrinfo(rai, addr, len, family, socktype, protocol, canonname, inspectname); + init_addrinfo(a, rai, addr, len, family, socktype, protocol, canonname, inspectname); return a; } @@ -1282,7 +1380,7 @@ call_getaddrinfo(VALUE node, VALUE service, hints.ai_flags = NUM2INT(flags); } - res = rsock_getaddrinfo(node, service, &hints, socktype_hack); + res = rsock_getaddrinfo(node, service, &hints, socktype_hack, timeout); if (res == NULL) rb_raise(rb_eSocket, "host not found"); @@ -1292,7 +1390,7 @@ call_getaddrinfo(VALUE node, VALUE service, static VALUE make_inspectname(VALUE node, VALUE service, struct addrinfo *res); static void -init_addrinfo_getaddrinfo(rb_addrinfo_t *rai, VALUE node, VALUE service, +init_addrinfo_getaddrinfo(VALUE self, rb_addrinfo_t *rai, VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE protocol, VALUE flags, VALUE inspectnode, VALUE inspectservice) { @@ -1306,7 +1404,7 @@ init_addrinfo_getaddrinfo(rb_addrinfo_t *rai, VALUE node, VALUE service, OBJ_FREEZE(canonname); } - init_addrinfo(rai, res->ai->ai_addr, res->ai->ai_addrlen, + init_addrinfo(self, rai, res->ai->ai_addr, res->ai->ai_addrlen, NUM2INT(family), NUM2INT(socktype), NUM2INT(protocol), canonname, inspectname); @@ -1418,7 +1516,7 @@ addrinfo_list_new(VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE #ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN static void -init_unix_addrinfo(rb_addrinfo_t *rai, VALUE path, int socktype) +init_unix_addrinfo(VALUE self, rb_addrinfo_t *rai, VALUE path, int socktype) { struct sockaddr_un un; socklen_t len; @@ -1434,7 +1532,7 @@ init_unix_addrinfo(rb_addrinfo_t *rai, VALUE path, int socktype) memcpy((void*)&un.sun_path, RSTRING_PTR(path), RSTRING_LEN(path)); len = rsock_unix_sockaddr_len(path); - init_addrinfo(rai, (struct sockaddr *)&un, len, + init_addrinfo(self, rai, (struct sockaddr *)&un, len, PF_UNIX, socktype, 0, Qnil, Qnil); } @@ -1538,7 +1636,7 @@ addrinfo_initialize(int argc, VALUE *argv, VALUE self) flags |= AI_NUMERICSERV; #endif - init_addrinfo_getaddrinfo(rai, numericnode, service, + init_addrinfo_getaddrinfo(self, rai, numericnode, service, INT2NUM(i_pfamily ? i_pfamily : af), INT2NUM(i_socktype), INT2NUM(i_protocol), INT2NUM(flags), nodename, service); @@ -1550,7 +1648,7 @@ addrinfo_initialize(int argc, VALUE *argv, VALUE self) { VALUE path = rb_ary_entry(sockaddr_ary, 1); StringValue(path); - init_unix_addrinfo(rai, path, SOCK_STREAM); + init_unix_addrinfo(self, rai, path, SOCK_STREAM); break; } #endif @@ -1563,7 +1661,7 @@ addrinfo_initialize(int argc, VALUE *argv, VALUE self) StringValue(sockaddr_arg); sockaddr_ptr = (struct sockaddr *)RSTRING_PTR(sockaddr_arg); sockaddr_len = RSTRING_SOCKLEN(sockaddr_arg); - init_addrinfo(rai, sockaddr_ptr, sockaddr_len, + init_addrinfo(self, rai, sockaddr_ptr, sockaddr_len, i_pfamily, i_socktype, i_protocol, canonname, inspectname); } @@ -2152,7 +2250,7 @@ addrinfo_mload(VALUE self, VALUE ary) } DATA_PTR(self) = rai = alloc_addrinfo(); - init_addrinfo(rai, &ss.addr, len, + init_addrinfo(self, rai, &ss.addr, len, pfamily, socktype, protocol, canonname, inspectname); return self; @@ -2920,7 +3018,7 @@ addrinfo_s_unix(int argc, VALUE *argv, VALUE self) addr = addrinfo_s_allocate(rb_cAddrinfo); DATA_PTR(addr) = rai = alloc_addrinfo(); - init_unix_addrinfo(rai, path, socktype); + init_unix_addrinfo(self, rai, path, socktype); return addr; } @@ -3007,6 +3105,99 @@ rsock_io_socket_addrinfo(VALUE io, struct sockaddr *addr, socklen_t len) UNREACHABLE_RETURN(Qnil); } +#if FAST_FALLBACK_INIT_INETSOCK_IMPL == 1 + +void +free_fast_fallback_getaddrinfo_shared(struct fast_fallback_getaddrinfo_shared **shared) +{ + xfree((*shared)->node); + (*shared)->node = NULL; + xfree((*shared)->service); + (*shared)->service = NULL; + rb_nativethread_lock_destroy(&(*shared)->lock); + free(*shared); + *shared = NULL; +} + +static void * +do_fast_fallback_getaddrinfo(void *ptr) +{ + struct fast_fallback_getaddrinfo_entry *entry = (struct fast_fallback_getaddrinfo_entry *)ptr; + struct fast_fallback_getaddrinfo_shared *shared = entry->shared; + int err = 0, shared_need_free = 0; + struct addrinfo *ai = NULL; + + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGPIPE); + pthread_sigmask(SIG_BLOCK, &set, NULL); + + err = numeric_getaddrinfo(shared->node, shared->service, &entry->hints, &entry->ai); + + if (err != 0) { + err = getaddrinfo(shared->node, shared->service, &entry->hints, &entry->ai); + #ifdef __linux__ + /* On Linux (mainly Ubuntu 13.04) /etc/nsswitch.conf has mdns4 and + * it cause getaddrinfo to return EAI_SYSTEM/ENOENT. [ruby-list:49420] + */ + if (err == EAI_SYSTEM && errno == ENOENT) + err = EAI_NONAME; + #endif + } + + /* for testing HEv2 */ + if (entry->test_sleep_ms > 0) { + struct timespec sleep_ts; + sleep_ts.tv_sec = entry->test_sleep_ms / 1000; + sleep_ts.tv_nsec = (entry->test_sleep_ms % 1000) * 1000000L; + if (sleep_ts.tv_nsec >= 1000000000L) { + sleep_ts.tv_sec += sleep_ts.tv_nsec / 1000000000L; + sleep_ts.tv_nsec = sleep_ts.tv_nsec % 1000000000L; + } + nanosleep(&sleep_ts, NULL); + } + if (entry->test_ecode != 0) { + err = entry->test_ecode; + if (entry->ai) { + freeaddrinfo(entry->ai); + entry->ai = NULL; + } + } + + rb_nativethread_lock_lock(&shared->lock); + { + entry->err = err; + const char notification = entry->family == AF_INET6 ? + IPV6_HOSTNAME_RESOLVED : IPV4_HOSTNAME_RESOLVED; + + if (shared->notify != -1 && (write(shared->notify, ¬ification, 1)) < 0) { + entry->err = errno; + entry->has_syserr = true; + } + if (--(entry->refcount) == 0) { + ai = entry->ai; + entry->ai = NULL; + } + if (--(shared->refcount) == 0) shared_need_free = 1; + } + rb_nativethread_lock_unlock(&shared->lock); + + if (ai) freeaddrinfo(ai); + if (shared_need_free && shared) { + free_fast_fallback_getaddrinfo_shared(&shared); + } + + return 0; +} + +void * +fork_safe_do_fast_fallback_getaddrinfo(void *ptr) +{ + return rb_thread_prevent_fork(do_fast_fallback_getaddrinfo, ptr); +} + +#endif + /* * Addrinfo class */ |
