This week I have found out how gdb get inferior's signal.
The magic is the TRACED flags!
The first instruction a inferior will execute after the first GDB run command is at 0x24f0 where is in /lib/ld.so _start() (macro RTLD_START defined in [glibc]/sysdeps/i386/dl_machine.h). Which will load the dynamic library and finally call init1()->_hurd_init()->_hurd_new_proc_init()->_hurdsig_init(). It will initialize the signal thread and let it listening on the inferior's msgport. The ptrace_me call will set the _hurdsig_traced variable (BTW, the gdb also will explicit set the _hurdsig_traced by msg_set_init_int() in if_set_traced()).
If _hurdsig_traced is set, whenever the inferior get any signal it will stop itself (by call proc_dostop) and call proc_mark_stop to notify its father task by send_sigal(SIGCHLD) or by pthread_cond_broadcast() (ps: I am not clear about this function). [glibc/hurd/hurdsig.c post_signal(): line754] When the inferior stop himself, the S_proc_wait() will returned[1](GDB has called this before), and send a reply message with msgID 24120 to GDB's event port. When GDB come back from the mach_msg(), it has known all things happened on inferior contains the signal of course.
These is exist an exception, GDB can post a signal to the inferior by command signal. This command will use a so called msg_sig_post_untraced() RPC, then the signal thread will not pass the untraced signal to GDB back.
[1]the manual page of wait
wait, waitpid, waitid - wait for process to change state. All of these system calls are used to wait for state changes in a child of the calling process, and obtain information about the child whose state has changed. A state change is considered to be: the child terminated; the child was stopped by a signal; or the child was resumed by a signal.