#include<stdio.h> #include<stdlib.h> #include<signal.h> #include<unistd.h> voidsig_handler(int num){ printf("\nrecvive the signal is %d\n", num); } intmain(){ int time = 20; signal(SIGINT, sig_handler); printf("enter to the sleep.\n");
do{ time = sleep(time); }while(time > 0); printf("sleep is over, main over.\n"); exit(0); }
/* * Set up the self-pipe that allows a signal handler to wake up the * select() in WaitLatch. Make the write-end non-blocking, so that * SetLatch won't block if the event has already been set many times * filling the kernel buffer. Make the read-end non-blocking too, so that * we can easily clear the pipe by reading until EAGAIN or EWOULDBLOCK. */ if (pipe(pipefd) < 0) ereport(FATAL, (errmsg("pipe() failed: %m"))); if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) < 0) ereport(FATAL, (errmsg("fcntl() failed on read-end of self-pipe: %m"))); if (fcntl(pipefd[1], F_SETFL, O_NONBLOCK) < 0) ereport(FATAL, (errmsg("fcntl() failed on write-end of self-pipe: %m")));
/* typedef in latch.h */ structWaitEventSet{ int nevents; /* number of registered events */ int nevents_space; /* maximum number of events in this set */
/* * Array, of nevents_space length, storing the definition of events this * set is waiting for. */ WaitEvent *events;
/* * If WL_LATCH_SET is specified in any wait event, latch is a pointer to * said latch, and latch_pos the offset in the ->events array. This is * useful because we check the state of the latch before performing doing * syscalls related to waiting. */ Latch *latch; // 数组记录该set下所有的latch = event int latch_pos;
int epoll_fd; /* epoll_wait returns events in a user provided arrays, allocate once */ structepoll_event *epoll_ret_events; };
// 每个epoll事件对应一个,也对应一个latch typedefstructWaitEvent{ int pos; /* position in the event data structure */ uint32 events; /* triggered events */ pgsocket fd; /* socket fd associated with event */ void *user_data; /* pointer provided in AddWaitEventToSet */ } WaitEvent;
/* * Sets a latch and wakes up anyone waiting on it. * * This is cheap if the latch is already set, otherwise not so much. * * NB: when calling this in a signal handler, be sure to save and restore * errno around it. (That's standard practice in most signal handlers, of * course, but we used to omit it in handlers that only set a flag.) */ voidSetLatch(volatile Latch* latch) { ThreadId owner_pid;
/* * The memory barrier has be to be placed here to ensure that any flag * variables possibly changed by this process have been flushed to main * memory, before we check/set is_set. */ pg_memory_barrier();
/* Quick exit if already set */ if (latch->is_set) return;
latch->is_set = true;
/* * See if anyone's waiting for the latch. It can be the current process if * we're in a signal handler. We use the self-pipe to wake up the select() * in that case. If it's another process, send a signal. * * Fetch owner_pid only once, in case the latch is concurrently getting * owned or disowned. XXX: This assumes that pid_t is atomic, which isn't * guaranteed to be true! In practice, the effective range of pid_t fits * in a 32 bit integer, and so should be atomic. In the worst case, we * might end up signaling the wrong process. Even then, you're very * unlucky if a process with that bogus pid exists and belongs to * openGauss; and PG database processes should handle excess SIGUSR1 * interrupts without a problem anyhow. * * Another sort of race condition that's possible here is for a new * process to own the latch immediately after we look, so we don't signal * it. This is okay so long as all callers of ResetLatch/WaitLatch follow * the standard coding convention of waiting at the bottom of their loops, * not the top, so that they'll correctly process latch-setting events * that happen before they enter the loop. */ owner_pid = latch->owner_pid; if (owner_pid == 0) return; elseif (owner_pid == t_thrd.proc_cxt.MyProcPid) { if (waiting) sendSelfPipeByte(); } else gs_signal_send(owner_pid, SIGUSR1); }
sendSelfPipeByte就是往管道写一个数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
staticvoidsendSelfPipeByte(void){ int rc; char dummy = 0; retry: rc = write(selfpipe_writefd, &dummy, 1); if (rc < 0) { /* If interrupted by signal, just retry */ if (errno == EINTR) goto retry; if (errno == EAGAIN || errno == EWOULDBLOCK) return; return; } }
而SIGUSR1信号的处理函数行为是:如果自己在等待,那么往管道写一个数据。
1 2 3
voidlatch_sigusr1_handler(void){ if (waiting) sendSelfPipeByte(); }