-
Notifications
You must be signed in to change notification settings - Fork 46
/
do_sigreturn.c
76 lines (65 loc) · 2.23 KB
/
do_sigreturn.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/**
* Syscall in this file: sigreturn
* Input: m1_i1: signum number
*
* Return: This syscall does not return
*
* @author Bruce Tan
* @email [email protected]
*
* @author Paul Monigatti
* @email [email protected]
*
* @create date 2017-08-23 06:10:17
*
*/
#include <kernel/kernel.h>
#include <winix/ksignal.h>
int do_sigreturn(struct proc *who, struct message *m){
reg_t *sp;
int signum = m->m1_i1;
sp = (reg_t*)get_physical_addr(who->ctx.m.sp, who);
sp += sizeof(struct sigframe);
// Copy the previous pcb saved on the user stack back
// to system proc struct, information includes registers
// scheduling flags, and messages
memcpy(who, sp, SIGNAL_CTX_LEN);
who->flags &= ~PROC_SIGAL_HANDLER;
// restore mask
who->sig_mask = who->sig_mask2;
if(signum == SIGABRT){
who->sig_table[SIGABRT].sa_handler = SIG_DFL;
send_sig(who, SIGABRT);
goto end;
}
// Normall after invoking a system call, the process
// will be blocked on STATE_RECEIVING reply from the system
// But since we have restored the pcb context before
// the signal handler, so double check process state,
// add it to scheduling queue if necessary
if(who->state == STATE_RUNNABLE)
enqueue_schedule(who);
end:
/**
* This is a nasty corner case here, if the signal handler
* is invoked while the process is blocked e.g. by wait(2),
* the state of the blocked process would be
* (STATE_RECEIVING | STATE_WAITING).
* if we would simply do syscall_reply(-EINTR, pnr, m), then
* only STATE_RECEIVING is cleared, STATE_WAITING is not. Since
* a process is only runnable if state == 0, the user space still
* wouldn't get the response.
*
* since we want to return -EINTR to the user, thus state has to be
* cleared, or equal to STATE_RUNNABLE, thus both RECEIVING AND WAITING
* need to be cleared.
*
* by making who->state = STATE_RECEIVING, we are ensuring that -EINTR
* is returned to the user space, and no other state info is blocking our way
*/
if(who->state & STATE_RECEIVING){
who->state = STATE_RECEIVING;
return -EINTR;
}
return DONTREPLY;
}