12. Understanding CURLOPT_NOSIGNAL Signals is a Unix concept where an asynchronous notification is sent to a process or to a specific thread within the same process in order to notify it of an event that occurred.
What does libcurl use signals for? When using the synchronous name resolver, libcurl uses alarm() to abort slow name resolves (if a timeout is set), which ultimately sends a SIGALARM to the process and is caught by libcurl
By default, libcurl installs its own sighandler while running, and restores the original one again on return – for SIGALARM and SIGPIPE.
Closing TLS (with OpenSSL etc) can trigger a SIGPIPE if the connection is dead.
Unless CURLOPT_NOSIGNAL is set! (default)
What does CURLOPT_NOSIGNAL do? It prevents libcurl from triggering signals
When disabled, it prevents libcurl from installing its own sighandler and…
Generated signals must then be handled by the libcurl-using application itself
627 /************************************************************* 628 * Set signal handler to catch SIGALRM 629 * Store the old value to be able to set it back later! 630 *************************************************************/ 631 #ifdef HAVE_SIGACTION 632 sigaction(SIGALRM, NULL, &sigact); 633 keep_sigact = sigact; 634 keep_copysig = TRUE; /* yes, we have a copy */ 635 sigact.sa_handler = alarmfunc; 636 #ifdef SA_RESTART 637 /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */ 638 sigact.sa_flags &= ~SA_RESTART; 639 #endif 640 /* now set the new struct */ 641 sigaction(SIGALRM, &sigact, NULL); 642 #else /* HAVE_SIGACTION */ 643 /* no sigaction(), revert to the much lamer signal() */ 644 #ifdef HAVE_SIGNAL 645 keep_sigact = signal(SIGALRM, alarmfunc); 646 #endif 647 #endif /* HAVE_SIGACTION */ 648 649 /* alarm() makes a signal get sent when the timeout fires off, and that 650 will abort system calls */ 651 prev_alarm = alarm(curlx_sltoui(timeout/1000L));
/* * Now find a thread we can wake up to take the signal off the queue. * * If the main thread wants the signal, it gets first crack. * Probably the least surprising to the average bear. */ if (wants_signal(sig, p)) t = p; else if (!group || thread_group_empty(p)) /* * There is just one thread and it does not need to be woken. * It will dequeue unblocked signals before it runs again. */ return; else { /* * Otherwise try to find a suitable thread. */ t = signal->curr_target; while (!wants_signal(sig, t)) { t = next_thread(t); if (t == signal->curr_target) /* * No thread needs to be woken. * Any eligible threads will see * the signal in the queue soon. */ return; } signal->curr_target = t; }
/* * Found a killable thread. If the signal will be fatal, * then start taking the whole group down immediately. */ if (sig_fatal(p, sig) && !(signal->flags & (SIGNAL_UNKILLABLE | SIGNAL_GROUP_EXIT)) && !sigismember(&t->real_blocked, sig) && (sig == SIGKILL || !t->ptrace)) { /* * This signal will be fatal to the whole group. */ if (!sig_kernel_coredump(sig)) { /* * Start a group exit and wake everybody up. * This way we don't have other threads * running and doing things after a slower * thread has the fatal signal pending. */ signal->flags = SIGNAL_GROUP_EXIT; signal->group_exit_code = sig; signal->group_stop_count = 0; t = p; do { task_clear_jobctl_pending(t, JOBCTL_PENDING_MASK); sigaddset(&t->pending.signal, SIGKILL); signal_wake_up(t, 1); } while_each_thread(p, t); return; } }
/* * The signal is already in the shared-pending queue. * Tell the chosen thread to wake up and dequeue it. */ signal_wake_up(t, sig == SIGKILL); return; }
#ifdef USE_ALARM_TIMEOUT /* * This signal handler jumps back into the main libcurl code and continues * execution. This effectively causes the remainder of the application to run * within a signal handler which is nonportable and could lead to problems. */ static RETSIGTYPE alarmfunc(int sig) { /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */ (void)sig; siglongjmp(curl_jmpenv, 1); return; } #endif /* USE_ALARM_TIMEOUT */
+#include <syscall.h> #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif @@ -619,7 +620,7 @@ int Curl_resolv_timeout(struct connectda before we invoke Curl_resolv() (and thus use "volatile"). */ if(sigsetjmp(curl_jmpenv, 1)) { /* this is coming from a siglongjmp() after an alarm signal */ - failf(data, "name lookup timed out"); + failf(data, "%d: name lookup timed out", syscall(SYS_gettid)); rc = CURLRESOLV_ERROR; goto clean_up; } @@ -646,6 +647,8 @@ int Curl_resolv_timeout(struct connectda #endif #endif /* HAVE_SIGACTION */
+ infof(conn->data, "%d: set alarm\n", syscall(SYS_gettid)); + /* alarm() makes a signal get sent when the timeout fires off, and that will abort system calls */ prev_alarm = alarm(curlx_sltoui(timeout/1000L));
修改代码后,编译使用同步DNS解析的静态库:
1 2 3
./buildconf ./configure --with-ssl --disable-threaded-resolver --enable-static --without-zlib make