Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

493 lines
12 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. sigsup.c
  5. Abstract:
  6. This provides support routines to implement signal delivery and dispatch.
  7. Author:
  8. Mark Lucovsky (markl) 30-Mar-1989
  9. Revision History:
  10. --*/
  11. #include "psxsrv.h"
  12. #define PENDING_SIGKILL (1<<SIGKILL)
  13. BOOLEAN
  14. PendingSignalHandledInside(
  15. IN PPSX_PROCESS p,
  16. IN PPSX_API_MSG m,
  17. IN sigset_t *RestoreBlockSigset OPTIONAL
  18. )
  19. /*++
  20. Routine Description:
  21. This procedure is called on system exit prior to reply generation. Its
  22. purpose is to test for the presence of pending signals, and if found, to
  23. process the signal.
  24. Arguments:
  25. p - Supplies the address of the process to be checked.
  26. m - Supplies the address of the process' current message.
  27. RestoreBlockSigset - Supplies an optional blocked signal mask that
  28. should be restored after the signal completes
  29. Locks - Process lock is released upon return.
  30. Return Value:
  31. TRUE - A pending signal was discovered that required extra time in the
  32. system, or the signal action caused the process to terminate. The
  33. process will be unlocked by this call, and no reply should be
  34. generated.
  35. FALSE - Either no pending signals were found, or a pending signal was
  36. processed. The contents of *m should be used to generate a reply.
  37. --*/
  38. {
  39. sigset_t Pending;
  40. ULONG Signal;
  41. ULONG SigAsMask;
  42. AcquireProcessLock(p);
  43. Pending = p->SignalDataBase.PendingSignalMask &
  44. ~p->SignalDataBase.BlockedSignalMask;
  45. if (!Pending) {
  46. //
  47. // Fast Path. Not pending, unblocked signals
  48. //
  49. ReleaseProcessLock(p);
  50. return FALSE;
  51. }
  52. //
  53. // Pending, Non-Blocked signals discovered
  54. //
  55. for (Signal = 1, SigAsMask = 1;
  56. Signal <= _SIGMAXSIGNO;
  57. Signal++, SigAsMask <<= 1L) {
  58. if (Pending & SigAsMask) {
  59. //
  60. // Make sure that if a SIGKILL is pending, the process is killed !
  61. //
  62. if (Pending & PENDING_SIGKILL) {
  63. SigAsMask = PENDING_SIGKILL;
  64. }
  65. //
  66. // Clear the signal
  67. //
  68. p->SignalDataBase.PendingSignalMask &= ~SigAsMask;
  69. switch ((ULONG_PTR)p->SignalDataBase.SignalDisposition[Signal-1].sa_handler) {
  70. case (ULONG_PTR)SIG_IGN:
  71. //
  72. // If signal is being ignored, then simply clearing its
  73. // pending bit "handles" the signal
  74. //
  75. break;
  76. case (ULONG_PTR)SIG_DFL:
  77. //
  78. // Do the default action associated with the signal
  79. //
  80. switch (Signal) {
  81. case SIGABRT:
  82. case SIGALRM:
  83. case SIGFPE:
  84. case SIGHUP:
  85. case SIGILL:
  86. case SIGINT:
  87. case SIGKILL:
  88. case SIGPIPE:
  89. case SIGQUIT:
  90. case SIGSEGV:
  91. case SIGTERM:
  92. case SIGUSR1:
  93. case SIGUSR2:
  94. //
  95. // Terminate Process. No reply will be generated. API Port
  96. // can be closed in terminate process.
  97. //
  98. ReleaseProcessLock(p);
  99. PsxTerminateProcessBySignal(p, m, Signal);
  100. return TRUE;
  101. case SIGCHLD:
  102. //
  103. // Default is to ignore this signal. Simply clear from
  104. // pending mask.
  105. //
  106. break;
  107. case SIGSTOP:
  108. PsxStopProcess(p, m, SIGSTOP, RestoreBlockSigset);
  109. return TRUE;
  110. case SIGTSTP:
  111. case SIGTTIN:
  112. case SIGTTOU:
  113. if (PsxStopProcess(p, m, Signal, RestoreBlockSigset)) {
  114. return TRUE;
  115. }
  116. AcquireProcessLock(p);
  117. break;
  118. case SIGCONT:
  119. //
  120. // Since process can not be active, and stopped at the same
  121. // time, a pending SIGCONT means that process is not
  122. // stopped so simply ignore the signal.
  123. //
  124. break;
  125. default:
  126. Panic("Unknown Pending Signal");
  127. break;
  128. }
  129. break;
  130. default:
  131. //
  132. // Signal is being caught
  133. //
  134. if ((Signal == SIGKILL) || (Signal == SIGSTOP)) {
  135. Panic("Catching SIGKILL or SIGSTOP");
  136. }
  137. if (m->Signal == SIGCONT) {
  138. // When a signal is being caught, we should
  139. // EINTR out.
  140. m->Signal = SIGALRM;
  141. }
  142. PsxDeliverSignal(p,Signal,RestoreBlockSigset);
  143. ReleaseProcessLock(p);
  144. return FALSE;
  145. }
  146. }
  147. }
  148. ReleaseProcessLock(p);
  149. return FALSE;
  150. }
  151. int
  152. PsxCheckPendingSignals(
  153. IN PPSX_PROCESS p
  154. )
  155. /*++
  156. Routine Description:
  157. This procedure is called from BlockProcess to see if the block should
  158. proceed, or if the block should be aborted due to a signal.
  159. This function is called with the process locked.
  160. Arguments:
  161. p - Supplies the address of the process to be checked.
  162. Return Value:
  163. Returns the number of the last pending signal, or 0 if there were no
  164. pending signals.
  165. --*/
  166. {
  167. sigset_t Pending;
  168. ULONG Signal;
  169. ULONG SigAsMask;
  170. int ReturnSignal = 0;
  171. Pending = p->SignalDataBase.PendingSignalMask &
  172. ~p->SignalDataBase.BlockedSignalMask;
  173. if (!Pending) {
  174. return 0; // no pending, unblocked signals
  175. }
  176. for(Signal = 1, SigAsMask = 1; Signal <= _SIGMAXSIGNO;
  177. Signal++, SigAsMask <<= 1L) {
  178. if (!(Pending & SigAsMask)) {
  179. continue; // this signal is not pending
  180. }
  181. switch ((ULONG_PTR)p->SignalDataBase.SignalDisposition[Signal - 1].sa_handler) {
  182. case (ULONG_PTR)SIG_IGN:
  183. //
  184. // If signal is being ignored, then simply
  185. // clearing its pending bit "handles" the
  186. // signal.
  187. //
  188. p->SignalDataBase.PendingSignalMask &=
  189. ~SigAsMask;
  190. break;
  191. case (ULONG_PTR)SIG_DFL:
  192. switch (Signal) {
  193. case SIGABRT:
  194. case SIGALRM:
  195. case SIGFPE:
  196. case SIGHUP:
  197. case SIGILL:
  198. case SIGINT:
  199. case SIGKILL:
  200. case SIGPIPE:
  201. case SIGQUIT:
  202. case SIGSEGV:
  203. case SIGTERM:
  204. case SIGUSR1:
  205. case SIGUSR2:
  206. //
  207. // The default action is to terminate. Don't
  208. // let the block proceed.
  209. //
  210. break;
  211. case SIGCHLD:
  212. //
  213. // Default is to ignore this signal. Clear
  214. // from pending mask.
  215. //
  216. p->SignalDataBase.PendingSignalMask &=
  217. ~SigAsMask;
  218. continue;
  219. case SIGSTOP:
  220. case SIGTSTP:
  221. case SIGTTIN:
  222. case SIGTTOU:
  223. //
  224. // Default action is to stop process. Don't
  225. // allow the process to be blocked.
  226. //
  227. break;
  228. case SIGCONT:
  229. //
  230. // SIGCONT is defaulted; the action is to
  231. // continue if stopped, ignore otherwise.
  232. // Here we suspect that the process is being
  233. // blocked, so we prevent that from happening.
  234. //
  235. break;
  236. default:
  237. Panic("Unknown Pending Signal");
  238. break;
  239. }
  240. ReturnSignal = Signal;
  241. break;
  242. default:
  243. //
  244. // This signal is handled.
  245. //
  246. ReturnSignal = Signal;
  247. }
  248. }
  249. return ReturnSignal;
  250. }
  251. VOID
  252. PsxDeliverSignal(
  253. IN PPSX_PROCESS p,
  254. IN ULONG Signal,
  255. IN sigset_t *RestoreBlockSigset OPTIONAL
  256. )
  257. /*++
  258. Routine Description:
  259. This function is used to deliver a signal to a process.
  260. This function is only called from PendingSignalHandledInside. It
  261. can safely assume that the target process is inside Psx.
  262. This function is called with the process locked.
  263. Arguments:
  264. p - Supplies the address of the process to be signaled
  265. Signal - Supplies the index of the signal to be delivered to the
  266. process
  267. RestoreBlockSigset - Supplies an optional blocked signal mask that
  268. should be restored after the signal completes
  269. Return Value:
  270. None.
  271. --*/
  272. {
  273. NTSTATUS st;
  274. sigset_t PreviousBlockMask;
  275. ULONG_PTR Args[3];
  276. PreviousBlockMask = ARGUMENT_PRESENT(RestoreBlockSigset) ?
  277. *RestoreBlockSigset :
  278. p->SignalDataBase.BlockedSignalMask;
  279. //
  280. // 1003.1-90 (3.3.4.2) -- When a signal is caught ... [the]
  281. // mask is formed by taking the union of the current signal
  282. // mask and the value of the sa_mask for the signal being
  283. // delivered, and then including the signal being delivered.
  284. //
  285. p->SignalDataBase.BlockedSignalMask |=
  286. p->SignalDataBase.SignalDisposition[Signal-1].sa_mask;
  287. SIGADDSET(&p->SignalDataBase.BlockedSignalMask, Signal);
  288. //
  289. // Arrange for call to signal deliverer
  290. //
  291. // r5 = PreviousBlockMask
  292. // r6 = Signal
  293. // r7 = Handler
  294. //
  295. {
  296. //
  297. // XXX.mjb: this code seems to fix problems in the MIPS
  298. // PP/signal_con test... I can't imagine why.
  299. //
  300. LARGE_INTEGER DelayInterval;
  301. DelayInterval.HighPart = 0;
  302. DelayInterval.LowPart = 0;
  303. NtDelayExecution(TRUE, &DelayInterval);
  304. }
  305. Args[0] = (ULONG)PreviousBlockMask;
  306. Args[1] = (ULONG)Signal;
  307. Args[2] = (ULONG_PTR)(p->SignalDataBase.SignalDisposition[Signal-1].sa_handler);
  308. st = RtlRemoteCall(
  309. p->Process,
  310. p->Thread,
  311. (PVOID)p->SignalDeliverer,
  312. 3,
  313. Args,
  314. TRUE,
  315. TRUE
  316. );
  317. if (!NT_SUCCESS(st)) {
  318. KdPrint(("PSXSS: PsxDeliverSignal: RtlRemoteCall: 0x%x\n", st));
  319. }
  320. }
  321. VOID
  322. PsxSigSuspendHandler(
  323. IN PPSX_PROCESS p,
  324. IN PINTCB IntControlBlock,
  325. IN PSX_INTERRUPTREASON InterruptReason,
  326. IN int Signal // Signal interrupting, if any
  327. )
  328. /*++
  329. Routine Description:
  330. This procedure is called when a signal is generated that should pop a
  331. process out of a sigsuspend system call. The procedure is called with the
  332. process locked. The main purpose of this function is to restore the
  333. blocked signal mask to its original value, deallocate the interrupt control
  334. block, and reply to the original call to sigsuspend. During the reply, the
  335. generated signal will be deliverd, or will cause the process to terminate.
  336. This function is responsible for unlocking the process.
  337. Arguments:
  338. p - Supplies the address of the process being interrupted.
  339. IntControlBlock - Supplies the address of the interrupt control block.
  340. InterruptReason - Supplies the reason that this process is being
  341. interrupted. Not used in this handler.
  342. Return Value:
  343. None.
  344. --*/
  345. {
  346. PPSX_API_MSG m;
  347. sigset_t RestoreBlockSigset;
  348. RtlLeaveCriticalSection(&BlockLock);
  349. RestoreBlockSigset = (sigset_t)((ULONG_PTR)IntControlBlock->IntContext);
  350. m = IntControlBlock->IntMessage;
  351. RtlFreeHeap(PsxHeap, 0,IntControlBlock);
  352. m->Error = EINTR;
  353. m->Signal = Signal;
  354. ApiReply(p, m, &RestoreBlockSigset);
  355. RtlFreeHeap(PsxHeap, 0, m);
  356. }