signal.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:11k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* $Id: signal.c,v 1.7 2000/09/05 21:44:54 davem Exp $
  2.  * signal.c: Signal emulation for Solaris
  3.  *
  4.  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  5.  */
  6. #include <linux/types.h>
  7. #include <linux/smp_lock.h>
  8. #include <asm/uaccess.h>
  9. #include <asm/svr4.h>
  10. #include <asm/string.h>
  11. #include "conv.h"
  12. #include "signal.h"
  13. #define _S(nr) (1L<<((nr)-1))
  14. #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
  15. long linux_to_solaris_signals[] = {
  16.         0,
  17. SOLARIS_SIGHUP, SOLARIS_SIGINT,
  18. SOLARIS_SIGQUIT, SOLARIS_SIGILL,
  19. SOLARIS_SIGTRAP, SOLARIS_SIGIOT,
  20. SOLARIS_SIGEMT, SOLARIS_SIGFPE,
  21. SOLARIS_SIGKILL, SOLARIS_SIGBUS,
  22. SOLARIS_SIGSEGV, SOLARIS_SIGSYS,
  23. SOLARIS_SIGPIPE, SOLARIS_SIGALRM,
  24. SOLARIS_SIGTERM, SOLARIS_SIGURG,
  25. SOLARIS_SIGSTOP, SOLARIS_SIGTSTP,
  26. SOLARIS_SIGCONT, SOLARIS_SIGCLD,
  27. SOLARIS_SIGTTIN, SOLARIS_SIGTTOU,
  28. SOLARIS_SIGPOLL, SOLARIS_SIGXCPU,
  29. SOLARIS_SIGXFSZ, SOLARIS_SIGVTALRM,
  30. SOLARIS_SIGPROF, SOLARIS_SIGWINCH,
  31. SOLARIS_SIGUSR1, SOLARIS_SIGUSR1,
  32. SOLARIS_SIGUSR2, -1,
  33. };
  34. long solaris_to_linux_signals[] = {
  35.         0,
  36.         SIGHUP, SIGINT, SIGQUIT, SIGILL,
  37.         SIGTRAP, SIGIOT, SIGEMT, SIGFPE,
  38.         SIGKILL, SIGBUS, SIGSEGV, SIGSYS,
  39.         SIGPIPE, SIGALRM, SIGTERM, SIGUSR1,
  40.         SIGUSR2, SIGCHLD, -1, SIGWINCH,
  41.         SIGURG, SIGPOLL, SIGSTOP, SIGTSTP,
  42.         SIGCONT, SIGTTIN, SIGTTOU, SIGVTALRM,
  43.         SIGPROF, SIGXCPU, SIGXFSZ,        -1,
  44. -1, -1, -1, -1,
  45. -1, -1, -1, -1,
  46. -1, -1, -1, -1,
  47. };
  48. static inline long mapsig(long sig)
  49. {
  50. if ((unsigned long)sig > SOLARIS_NSIGNALS)
  51. return -EINVAL;
  52. return solaris_to_linux_signals[sig];
  53. }
  54. asmlinkage int solaris_kill(int pid, int sig)
  55. {
  56. int (*sys_kill)(int,int) = 
  57. (int (*)(int,int))SYS(kill);
  58. int s = mapsig(sig);
  59. if (s < 0) return s;
  60. return sys_kill(pid, s);
  61. }
  62. static long sig_handler(int sig, u32 arg, int one_shot)
  63. {
  64. struct sigaction sa, old;
  65. int ret;
  66. mm_segment_t old_fs = get_fs();
  67. int (*sys_sigaction)(int,struct sigaction *,struct sigaction *) = 
  68. (int (*)(int,struct sigaction *,struct sigaction *))SYS(sigaction);
  69. sigemptyset(&sa.sa_mask);
  70. sa.sa_restorer = NULL;
  71. sa.sa_handler = (__sighandler_t)A(arg);
  72. sa.sa_flags = 0;
  73. if (one_shot) sa.sa_flags = SA_ONESHOT | SA_NOMASK;
  74. set_fs (KERNEL_DS);
  75. ret = sys_sigaction(sig, &sa, &old);
  76. set_fs (old_fs);
  77. if (ret < 0) return ret;
  78. return (u32)(long)old.sa_handler;
  79. }
  80. static inline long solaris_signal(int sig, u32 arg)
  81. {
  82. return sig_handler (sig, arg, 1);
  83. }
  84. static long solaris_sigset(int sig, u32 arg)
  85. {
  86. if (arg != 2) /* HOLD */ {
  87. spin_lock_irq(&current->sigmask_lock);
  88. sigdelsetmask(&current->blocked, _S(sig));
  89. recalc_sigpending(current);
  90. spin_unlock_irq(&current->sigmask_lock);
  91. return sig_handler (sig, arg, 0);
  92. } else {
  93. spin_lock_irq(&current->sigmask_lock);
  94. sigaddsetmask(&current->blocked, (_S(sig) & ~_BLOCKABLE));
  95. recalc_sigpending(current);
  96. spin_unlock_irq(&current->sigmask_lock);
  97. return 0;
  98. }
  99. }
  100. static inline long solaris_sighold(int sig)
  101. {
  102. return solaris_sigset(sig, 2);
  103. }
  104. static inline long solaris_sigrelse(int sig)
  105. {
  106. spin_lock_irq(&current->sigmask_lock);
  107. sigdelsetmask(&current->blocked, _S(sig));
  108. recalc_sigpending(current);
  109. spin_unlock_irq(&current->sigmask_lock);
  110. return 0;
  111. }
  112. static inline long solaris_sigignore(int sig)
  113. {
  114. return sig_handler (sig, (u32)SIG_IGN, 0);
  115. }
  116. static inline long solaris_sigpause(int sig)
  117. {
  118. printk ("Need to support solaris sigpausen");
  119. return -ENOSYS;
  120. }
  121. asmlinkage long solaris_sigfunc(int sig, u32 arg)
  122. {
  123. int func = sig & ~0xff;
  124. sig = mapsig(sig & 0xff); 
  125. if (sig < 0) return sig; 
  126. switch (func) {
  127. case 0: return solaris_signal(sig, arg); 
  128. case 0x100: return solaris_sigset(sig, arg); 
  129. case 0x200: return solaris_sighold(sig);
  130. case 0x400: return solaris_sigrelse(sig); 
  131. case 0x800: return solaris_sigignore(sig); 
  132. case 0x1000: return solaris_sigpause(sig);
  133. }
  134. return -EINVAL;
  135. }
  136. typedef struct {
  137. u32 __sigbits[4];
  138. } sol_sigset_t;
  139. static inline int mapin(u32 *p, sigset_t *q)
  140. {
  141. int i;
  142. u32 x;
  143. int sig;
  144. sigemptyset(q);
  145. x = p[0];
  146. for (i = 1; i <= SOLARIS_NSIGNALS; i++) {
  147. if (x & 1) {
  148. sig = solaris_to_linux_signals[i];
  149. if (sig == -1)
  150. return -EINVAL;
  151. sigaddsetmask(q, (1L << (sig - 1)));
  152. }
  153. x >>= 1;
  154. if (i == 32)
  155. x = p[1];
  156. }
  157. return 0;
  158. }
  159. static inline int mapout(sigset_t *q, u32 *p)
  160. {
  161. int i;
  162. int sig;
  163. p[0] = 0;
  164. p[1] = 0;
  165. for (i = 1; i <= 32; i++) {
  166. if (sigismember(q, sigmask(i))) {
  167. sig = linux_to_solaris_signals[i];
  168. if (sig == -1)
  169. return -EINVAL;
  170. if (sig > 32)
  171. p[1] |= 1L << (sig - 33);
  172. else
  173. p[0] |= 1L << (sig - 1);
  174. }
  175. }
  176. return 0;
  177. }
  178. asmlinkage int solaris_sigprocmask(int how, u32 in, u32 out)
  179. {
  180. sigset_t in_s, *ins, out_s, *outs;
  181. mm_segment_t old_fs = get_fs();
  182. int ret;
  183. int (*sys_sigprocmask)(int,sigset_t *,sigset_t *) = 
  184. (int (*)(int,sigset_t *,sigset_t *))SYS(sigprocmask);
  185. ins = NULL; outs = NULL;
  186. if (in) {
  187. u32 tmp[2];
  188. if (copy_from_user (tmp, (sol_sigset_t *)A(in), 2*sizeof(u32)))
  189. return -EFAULT;
  190. ins = &in_s;
  191. if (mapin (tmp, ins)) return -EINVAL;
  192. }
  193. if (out) outs = &out_s;
  194. set_fs (KERNEL_DS);
  195. ret = sys_sigprocmask((how == 3) ? SIG_SETMASK : how, ins, outs);
  196. set_fs (old_fs);
  197. if (ret) return ret;
  198. if (out) {
  199. u32 tmp[4];
  200. tmp[2] = 0; tmp[3] = 0;
  201. if (mapout (outs, tmp)) return -EINVAL;
  202. if (copy_to_user((sol_sigset_t *)A(out), tmp, 4*sizeof(u32)))
  203. return -EFAULT;
  204. }
  205. return 0;
  206. }
  207. asmlinkage long do_sol_sigsuspend(u32 mask)
  208. {
  209. sigset_t s;
  210. u32 tmp[2];
  211. if (copy_from_user (tmp, (sol_sigset_t *)A(mask), 2*sizeof(u32)))
  212. return -EFAULT;
  213. if (mapin (tmp, &s)) return -EINVAL;
  214. return (long)s.sig[0];
  215. }
  216. struct sol_sigaction {
  217. int sa_flags;
  218. u32 sa_handler;
  219. u32 sa_mask[4];
  220. int sa_resv[2];
  221. };
  222. asmlinkage int solaris_sigaction(int sig, u32 act, u32 old)
  223. {
  224. u32 tmp, tmp2[4];
  225. struct sigaction s, s2;
  226. int ret;
  227. mm_segment_t old_fs = get_fs();
  228. int (*sys_sigaction)(int,struct sigaction *,struct sigaction *) = 
  229. (int (*)(int,struct sigaction *,struct sigaction *))SYS(sigaction);
  230. sig = mapsig(sig); 
  231. if (sig < 0) {
  232. /* We cheat a little bit for Solaris only signals */
  233. if (old && clear_user((struct sol_sigaction *)A(old), sizeof(struct sol_sigaction)))
  234. return -EFAULT;
  235. return 0;
  236. }
  237. if (act) {
  238. if (get_user (tmp, &((struct sol_sigaction *)A(act))->sa_flags))
  239. return -EFAULT;
  240. s.sa_flags = 0;
  241. if (tmp & SOLARIS_SA_ONSTACK) s.sa_flags |= SA_STACK;
  242. if (tmp & SOLARIS_SA_RESTART) s.sa_flags |= SA_RESTART;
  243. if (tmp & SOLARIS_SA_NODEFER) s.sa_flags |= SA_NOMASK;
  244. if (tmp & SOLARIS_SA_RESETHAND) s.sa_flags |= SA_ONESHOT;
  245. if (tmp & SOLARIS_SA_NOCLDSTOP) s.sa_flags |= SA_NOCLDSTOP;
  246. if (get_user (tmp, &((struct sol_sigaction *)A(act))->sa_handler) ||
  247.     copy_from_user (tmp2, &((struct sol_sigaction *)A(act))->sa_mask, 2*sizeof(u32)))
  248. return -EFAULT;
  249. s.sa_handler = (__sighandler_t)A(tmp);
  250. if (mapin (tmp2, &s.sa_mask)) return -EINVAL;
  251. s.sa_restorer = 0;
  252. }
  253. set_fs(KERNEL_DS);
  254. ret = sys_sigaction(sig, act ? &s : NULL, old ? &s2 : NULL);
  255. set_fs(old_fs);
  256. if (ret) return ret;
  257. if (old) {
  258. if (mapout (&s2.sa_mask, tmp2)) return -EINVAL;
  259. tmp = 0; tmp2[2] = 0; tmp2[3] = 0;
  260. if (s2.sa_flags & SA_STACK) tmp |= SOLARIS_SA_ONSTACK;
  261. if (s2.sa_flags & SA_RESTART) tmp |= SOLARIS_SA_RESTART;
  262. if (s2.sa_flags & SA_NOMASK) tmp |= SOLARIS_SA_NODEFER;
  263. if (s2.sa_flags & SA_ONESHOT) tmp |= SOLARIS_SA_RESETHAND;
  264. if (s2.sa_flags & SA_NOCLDSTOP) tmp |= SOLARIS_SA_NOCLDSTOP;
  265. if (put_user (tmp, &((struct sol_sigaction *)A(old))->sa_flags) ||
  266.     __put_user ((u32)(long)s2.sa_handler, &((struct sol_sigaction *)A(old))->sa_handler) ||
  267.     copy_to_user (&((struct sol_sigaction *)A(old))->sa_mask, tmp2, 4*sizeof(u32)))
  268. return -EFAULT;
  269. }
  270. return 0;
  271. }
  272. asmlinkage int solaris_sigpending(int which, u32 set)
  273. {
  274. sigset_t s;
  275. u32 tmp[4];
  276. switch (which) {
  277. case 1: /* sigpending */
  278. spin_lock_irq(&current->sigmask_lock);
  279. sigandsets(&s, &current->blocked, &current->pending.signal);
  280. recalc_sigpending(current);
  281. spin_unlock_irq(&current->sigmask_lock);
  282. break;
  283. case 2: /* sigfillset - I just set signals which have linux equivalents */
  284. sigfillset(&s);
  285. break;
  286. default: return -EINVAL;
  287. }
  288. if (mapout (&s, tmp)) return -EINVAL;
  289. tmp[2] = 0; tmp[3] = 0;
  290. if (copy_to_user ((u32 *)A(set), tmp, sizeof(tmp)))
  291. return -EFAULT;
  292. return 0;
  293. }
  294. asmlinkage int solaris_wait(u32 stat_loc)
  295. {
  296. int (*sys_wait4)(pid_t,unsigned int *, int, struct rusage *) =
  297. (int (*)(pid_t,unsigned int *, int, struct rusage *))SYS(wait4);
  298. int ret, status;
  299. ret = sys_wait4(-1, (unsigned int *)A(stat_loc), WUNTRACED, NULL);
  300. if (ret >= 0 && stat_loc) {
  301. if (get_user (status, (unsigned int *)A(stat_loc)))
  302. return -EFAULT;
  303. if (((status - 1) & 0xffff) < 0xff)
  304. status = linux_to_solaris_signals[status & 0x7f] & 0x7f;
  305. else if ((status & 0xff) == 0x7f)
  306. status = (linux_to_solaris_signals[(status >> 8) & 0xff] << 8) | 0x7f;
  307. if (__put_user (status, (unsigned int *)A(stat_loc)))
  308. return -EFAULT;
  309. }
  310. return ret;
  311. }
  312. asmlinkage int solaris_waitid(int idtype, s32 pid, u32 info, int options)
  313. {
  314. int (*sys_wait4)(pid_t,unsigned int *, int, struct rusage *) =
  315. (int (*)(pid_t,unsigned int *, int, struct rusage *))SYS(wait4);
  316. int opts, status, ret;
  317. switch (idtype) {
  318. case 0: /* P_PID */ break;
  319. case 1: /* P_PGID */ pid = -pid; break;
  320. case 7: /* P_ALL */ pid = -1; break;
  321. default: return -EINVAL;
  322. }
  323. opts = 0;
  324. if (options & SOLARIS_WUNTRACED) opts |= WUNTRACED;
  325. if (options & SOLARIS_WNOHANG) opts |= WNOHANG;
  326. current->state = TASK_RUNNING;
  327. ret = sys_wait4(pid, (unsigned int *)A(info), opts, NULL);
  328. if (ret < 0) return ret;
  329. if (info) {
  330. struct sol_siginfo *s = (struct sol_siginfo *)A(info);
  331. if (get_user (status, (unsigned int *)A(info)))
  332. return -EFAULT;
  333. if (__put_user (SOLARIS_SIGCLD, &s->si_signo) ||
  334.     __put_user (ret, &s->_data._proc._pid))
  335. return -EFAULT;
  336. switch (status & 0xff) {
  337. case 0: ret = SOLARIS_CLD_EXITED;
  338. status = (status >> 8) & 0xff;
  339. break;
  340. case 0x7f:
  341. status = (status >> 8) & 0xff;
  342. switch (status) {
  343. case SIGSTOP:
  344. case SIGTSTP: ret = SOLARIS_CLD_STOPPED;
  345. default: ret = SOLARIS_CLD_EXITED;
  346. }
  347. status = linux_to_solaris_signals[status];
  348. break;
  349. default:
  350. if (status & 0x80) ret = SOLARIS_CLD_DUMPED;
  351. else ret = SOLARIS_CLD_KILLED;
  352. status = linux_to_solaris_signals[status & 0x7f];
  353. break;
  354. }
  355. if (__put_user (ret, &s->si_code) ||
  356.     __put_user (status, &s->_data._proc._pdata._cld._status))
  357. return -EFAULT;
  358. }
  359. return 0;
  360. }
  361. extern int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs);
  362. extern int svr4_getcontext(svr4_ucontext_t *c, struct pt_regs *regs);
  363. asmlinkage int solaris_context(struct pt_regs *regs)
  364. {
  365. switch ((unsigned)regs->u_regs[UREG_I0]) {
  366. case 0: /* getcontext */
  367. return svr4_getcontext((svr4_ucontext_t *)(long)(u32)regs->u_regs[UREG_I1], regs);
  368. case 1: /* setcontext */
  369. return svr4_setcontext((svr4_ucontext_t *)(long)(u32)regs->u_regs[UREG_I1], regs);
  370. default:
  371. return -EINVAL;
  372. }
  373. }
  374. asmlinkage int solaris_sigaltstack(u32 ss, u32 oss)
  375. {
  376. /* XXX Implement this soon */
  377. return 0;
  378. }