xref: /original-bsd/sys/kern/uipc_mu_msg.c (revision f0fd5f8a)
1 /*	uipc_mu_msg.c	Melb 4.2	82/11/13	*/
2 
3 #ifdef	MUSH
4 #include "../h/param.h"
5 #include "../h/dir.h"
6 #include "../h/user.h"
7 #include "../h/proc.h"
8 
9 /*
10  * Melbourne Trivial IPC mechanism
11  *
12  *	This is intended solely to serve for the 4.1bsd MUSH implementation
13  *	until a better IPC scheme arrives from somewhere
14  *
15  *	If it happens to be useful for other purposes, OK, but users
16  *	should be prepared to change at short (no) notice.
17  *	This is purposely kept as small as possible, with the expectation
18  *	than anything done using this scheme should be able to be
19  *	done easily in any other, with possibly a little more legwork.
20  *
21  *	NB: we don't go fooling with spl's in here, as it is deliberately
22  *	not intended that interrupt level code will ever call this
23  */
24 
25 mu_msg()
26 {
27 	register struct proc *p, *pp;
28 	mmsgbuf mb;
29 	register struct a {
30 		msg_type	cmd;
31 		int		wait;	/* bit mask - see mu_msg.h */
32 		mmsgbuf	*	msgp;
33 	} *uap;
34 
35 	uap = (struct a *)u.u_ap;
36 	p = u.u_procp;
37 
38 	for (;;) {	/* only loop if cmd == MSG_SNDW */
39 		switch (uap->cmd) {
40 
41 		case MSG_ENAB:
42 			p->p_msgflgs |= MSGENAB;
43 			return;
44 
45 		case MSG_DISB:
46 			p->p_msgflgs &= ~MSGENAB;
47 				/*
48 				 * Q: what should be done with a pending msg
49 				 * - for now we will just leave it, proc should
50 				 * do a MSG_RECV w/o waiting after MSG_DISB
51 				 */
52 			return;
53 
54 		case MSG_RECV:
55 			while (!p->p_mb.msg_val && (uap->wait & MSG_W_RCV)) {
56 				p->p_msgflgs |= MSGOK;
57 				sleep((caddr_t) &p->p_mb, MSGPRI);
58 			}
59 			if (copyout((caddr_t)&p->p_mb, (caddr_t)uap->msgp,
60 			    sizeof(mmsgbuf)))
61 				u.u_error = EFAULT;
62 			p->p_msgflgs &= ~(MSGOK|MSGWRPLY);
63 			if (p->p_mb.msg_rply)
64 				p->p_msgflgs |= MSGRPLY;
65 			else {
66 				p->p_mb.msg_val = 0;
67 				if (p->p_msgflgs & MSGWAIT) {
68 					p->p_msgflgs &= ~MSGWAIT;
69 					wakeup((caddr_t)&p->p_mb);
70 				}
71 			}
72 			return;
73 
74 		case MSG_SEND:
75 		case MSG_SNDW:
76 		case MSG_RPLY:
77 			if (copyin((caddr_t)uap->msgp, (caddr_t)&mb,
78 			    sizeof(mmsgbuf))) {
79 				u.u_error = EFAULT;
80 				return;
81 			}
82 			if (uap->cmd == MSG_RPLY) {
83 				if (!(p->p_msgflgs & MSGRPLY) ||
84 				    mb.msg_pid != p->p_mb.msg_pid) {
85 					u.u_error = EINVAL;
86 					return;
87 				}
88 				p->p_mb.msg_val = 0;
89 				if (!mb.msg_rply && p->p_msgflgs & MSGWAIT) {
90 					p->p_msgflgs &= ~MSGWAIT;
91 					wakeup((caddr_t)&p->p_mb);
92 				}
93 			} else {
94 				if (p->p_msgflgs & MSGRPLY) {
95 					while (pp = mu_send(&p->p_mb,
96 					    (int)p->p_mb.msg_pid, 0)) {
97 						pp->p_msgflgs |= MSGWAIT;
98 						sleep((caddr_t)&pp->p_mb,
99 						    MSGPRI);
100 					}
101 					u.u_error = 0; /* not err if exited */
102 					p->p_mb.msg_val = 0;
103 					if (!mb.msg_rply &&
104 					    p->p_msgflgs & MSGWAIT) {
105 						p->p_msgflgs &= ~MSGWAIT;
106 						wakeup((caddr_t)&p->p_mb);
107 					}
108 				}
109 			}
110 			p->p_msgflgs &= ~MSGRPLY;
111 			if (mb.msg_rply) {
112 				if (p->p_mb.msg_val) {
113 					u.u_error = ENOSPC;
114 					return;
115 				}
116 				p->p_mb = mb;
117 				p->p_mb.msg_rply = 0;
118 				p->p_mb.msg_val = 0;
119 				p->p_msgflgs |= MSGWRPLY;
120 			}
121 			mb.msg_uid = u.u_uid;
122 			while ((pp = mu_send(&mb, (int)mb.msg_pid, p->p_pid)) &&
123 			    uap->wait & MSG_W_POST) {
124 				pp->p_msgflgs |= MSGWAIT;
125 				sleep((caddr_t)&pp->p_mb, MSGPRI);
126 			}
127 			if (pp)
128 				u.u_error = EBUSY;
129 			if (u.u_error) {
130 				if (mb.msg_rply)
131 					p->p_msgflgs &= ~MSGWRPLY;
132 				return;
133 			}
134 			if (uap->cmd == MSG_SNDW) {
135 				uap->cmd = MSG_RECV;
136 				break;
137 			}
138 			return;
139 
140 		default:
141 			u.u_error = EINVAL;
142 			return;
143 		}
144 	}
145 }
146 
147 struct proc *
148 mu_send(mp, pid, from)
149 	register mmsgbuf *mp;
150 	register int pid, from;
151 {
152 	register struct proc *p;
153 
154 	p = pfind(pid);
155 
156 	if (p == NULL || p->p_stat == SZOMB ||
157 	    !(p->p_msgflgs & (MSGOK|MSGENAB|MSGWRPLY))) {
158 		u.u_error = ESRCH;
159 		return((struct proc *)0);
160 	}
161 
162 	if (p->p_mb.msg_val ||
163 	    from != 0 && p->p_msgflgs&MSGWRPLY && from != p->p_mb.msg_pid)
164 		return(p);
165 
166 	p->p_mb = *mp;
167 	p->p_mb.msg_val = 1;
168 	p->p_mb.msg_pid = from;
169 	if (from == 0)
170 		p->p_mb.msg_rply = 0;
171 	if (p->p_msgflgs & MSGOK)
172 		wakeup((caddr_t)&p->p_mb);
173 	else if (p->p_msgflgs & MSGENAB)
174 		psignal(p, SIGMESG);
175 	return((struct proc *)0);
176 }
177 
178 msgto(pid, data)
179 int pid;
180 DATA_T data;
181 {
182 	register struct proc *p;
183 	mmsgbuf mb;
184 
185 	mb.msg_uid = 0;		/* all msgs from system are from root */
186 	mb.msg_data = data;
187 	mb.msg_rply = 0;
188 	while (p = mu_send(&mb, pid, u.u_procp->p_pid)) {
189 		p->p_msgflgs |= MSGWAIT;
190 		sleep((caddr_t)&p->p_mb, MSGPRI);
191 	}
192 }
193 #endif
194