comparison svr-chansession.c @ 1495:0c16b4ccbd54

make signal flags volatile, simplify handling
author Matt Johnston <matt@ucc.asn.au>
date Wed, 14 Feb 2018 23:06:01 +0800
parents 58a74cb829b8
children da3bed08607b
comparison
equal deleted inserted replaced
1494:da095983a60b 1495:0c16b4ccbd54
78 struct ChanSess *chansess = (struct ChanSess*)channel->typedata; 78 struct ChanSess *chansess = (struct ChanSess*)channel->typedata;
79 TRACE(("sesscheckclose, pid is %d", chansess->exit.exitpid)) 79 TRACE(("sesscheckclose, pid is %d", chansess->exit.exitpid))
80 return chansess->exit.exitpid != -1; 80 return chansess->exit.exitpid != -1;
81 } 81 }
82 82
83 void svr_chansess_checksignal(void) {
84 int status;
85 pid_t pid;
86
87 if (!ses.channel_signal_pending) {
88 return;
89 }
90
91 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
92 unsigned int i;
93 struct exitinfo *ex = NULL;
94 TRACE(("sigchld handler: pid %d", pid))
95
96 ex = NULL;
97 /* find the corresponding chansess */
98 for (i = 0; i < svr_ses.childpidsize; i++) {
99 if (svr_ses.childpids[i].pid == pid) {
100 TRACE(("found match session"));
101 ex = &svr_ses.childpids[i].chansess->exit;
102 break;
103 }
104 }
105
106 /* If the pid wasn't matched, then we might have hit the race mentioned
107 * above. So we just store the info for the parent to deal with */
108 if (ex == NULL) {
109 TRACE(("using lastexit"));
110 ex = &svr_ses.lastexit;
111 }
112
113 ex->exitpid = pid;
114 if (WIFEXITED(status)) {
115 ex->exitstatus = WEXITSTATUS(status);
116 }
117 if (WIFSIGNALED(status)) {
118 ex->exitsignal = WTERMSIG(status);
119 #if !defined(AIX) && defined(WCOREDUMP)
120 ex->exitcore = WCOREDUMP(status);
121 #else
122 ex->exitcore = 0;
123 #endif
124 } else {
125 /* we use this to determine how pid exited */
126 ex->exitsignal = -1;
127 }
128
129 }
130 }
131
83 /* Handler for childs exiting, store the state for return to the client */ 132 /* Handler for childs exiting, store the state for return to the client */
84 133
85 /* There's a particular race we have to watch out for: if the forked child 134 /* There's a particular race we have to watch out for: if the forked child
86 * executes, exits, and this signal-handler is called, all before the parent 135 * executes, exits, and this signal-handler is called, all before the parent
87 * gets to run, then the childpids[] array won't have the pid in it. Hence we 136 * gets to run, then the childpids[] array won't have the pid in it. Hence we
88 * use the svr_ses.lastexit struct to hold the exit, which is then compared by 137 * use the svr_ses.lastexit struct to hold the exit, which is then compared by
89 * the parent when it runs. This work correctly at least in the case of a 138 * the parent when it runs. This work correctly at least in the case of a
90 * single shell spawned (ie the usual case) */ 139 * single shell spawned (ie the usual case) */
91 static void sesssigchild_handler(int UNUSED(dummy)) { 140 static void sesssigchild_handler(int UNUSED(dummy)) {
92
93 int status;
94 pid_t pid;
95 unsigned int i; 141 unsigned int i;
96 struct sigaction sa_chld; 142 struct sigaction sa_chld;
97 struct exitinfo *exit = NULL;
98 143
99 const int saved_errno = errno; 144 const int saved_errno = errno;
100 145
101 /* Make channel handling code look for closed channels */
102 ses.channel_signal_pending = 1;
103
104 TRACE(("enter sigchld handler")) 146 TRACE(("enter sigchld handler"))
105 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { 147
106 TRACE(("sigchld handler: pid %d", pid)) 148 /* Make sure that the main select() loop wakes up */
107 149 while (1) {
108 exit = NULL; 150 /* isserver is just a random byte to write. We can't do anything
109 /* find the corresponding chansess */ 151 about an error so should just ignore it */
110 for (i = 0; i < svr_ses.childpidsize; i++) { 152 if (write(ses.signal_pipe[1], &ses.isserver, 1) == 1
111 if (svr_ses.childpids[i].pid == pid) { 153 || errno != EINTR) {
112 TRACE(("found match session")); 154 break;
113 exit = &svr_ses.childpids[i].chansess->exit;
114 break;
115 }
116 }
117
118 /* If the pid wasn't matched, then we might have hit the race mentioned
119 * above. So we just store the info for the parent to deal with */
120 if (exit == NULL) {
121 TRACE(("using lastexit"));
122 exit = &svr_ses.lastexit;
123 }
124
125 exit->exitpid = pid;
126 if (WIFEXITED(status)) {
127 exit->exitstatus = WEXITSTATUS(status);
128 }
129 if (WIFSIGNALED(status)) {
130 exit->exitsignal = WTERMSIG(status);
131 #if !defined(AIX) && defined(WCOREDUMP)
132 exit->exitcore = WCOREDUMP(status);
133 #else
134 exit->exitcore = 0;
135 #endif
136 } else {
137 /* we use this to determine how pid exited */
138 exit->exitsignal = -1;
139 }
140
141 /* Make sure that the main select() loop wakes up */
142 while (1) {
143 /* isserver is just a random byte to write. We can't do anything
144 about an error so should just ignore it */
145 if (write(ses.signal_pipe[1], &ses.isserver, 1) == 1
146 || errno != EINTR) {
147 break;
148 }
149 } 155 }
150 } 156 }
151 157
152 sa_chld.sa_handler = sesssigchild_handler; 158 sa_chld.sa_handler = sesssigchild_handler;
153 sa_chld.sa_flags = SA_NOCLDSTOP; 159 sa_chld.sa_flags = SA_NOCLDSTOP;