Remove building with NOCRYPTO option
[minix.git] / minix / servers / ipc / main.c
blob02c62c42718785e8a47ab26ec6090c130864645d
1 #include "inc.h"
3 #define SEM_EVENTS 0x01 /* semaphore code wants process events */
4 static unsigned int event_mask = 0;
6 static int verbose = 0;
8 /*
9 * The call table for this service.
11 #define CALL(n) [((n) - IPC_BASE)]
12 static int (* const call_vec[])(message *) = {
13 CALL(IPC_SHMGET) = do_shmget,
14 CALL(IPC_SHMAT) = do_shmat,
15 CALL(IPC_SHMDT) = do_shmdt,
16 CALL(IPC_SHMCTL) = do_shmctl,
17 CALL(IPC_SEMGET) = do_semget,
18 CALL(IPC_SEMCTL) = do_semctl,
19 CALL(IPC_SEMOP) = do_semop,
23 * Remote MIB implementation of CTL_KERN KERN_SYSVIPC KERN_SYSVIPC_INFO. This
24 * function handles all queries on the "kern.ipc.sysvipc_info" sysctl(2) node.
26 static ssize_t
27 kern_ipc_info(struct rmib_call * call, struct rmib_node * node __unused,
28 struct rmib_oldp * oldp, struct rmib_newp * newp __unused)
31 if (call->call_namelen != 1)
32 return EINVAL;
35 * Let each IPC submodule provide information through it own function.
36 * An important security note: unlike IPC_STAT and the like, access to
37 * the sysvipc_info node does not require root privileges. That is: on
38 * NetBSD, any user can get a full listing of all IPC objects in the
39 * system. We therefore do not perform any security check here.
41 switch (call->call_name[0]) {
42 case KERN_SYSVIPC_SEM_INFO:
43 return get_sem_mib_info(oldp);
45 case KERN_SYSVIPC_SHM_INFO:
46 return get_shm_mib_info(oldp);
48 default:
49 return EOPNOTSUPP;
53 /* The CTL_KERN KERN_SYSVIPC subtree. */
54 static struct rmib_node kern_ipc_table[] = {
55 /* 1*/ [KERN_SYSVIPC_INFO] = RMIB_FUNC(RMIB_RO | CTLTYPE_NODE, 0,
56 kern_ipc_info, "sysvipc_info",
57 "System V style IPC information"),
58 /* 2*/ [KERN_SYSVIPC_MSG] = RMIB_INT(RMIB_RO, 0, "sysvmsg", "System V "
59 "style message support available"),
60 /* 3*/ [KERN_SYSVIPC_SEM] = RMIB_INT(RMIB_RO, 1, "sysvsem", "System V "
61 "style semaphore support available"),
62 /* 4*/ [KERN_SYSVIPC_SHM] = RMIB_INT(RMIB_RO, 1, "sysvshm", "System V "
63 "style shared memory support available"),
64 /* 5*/ /* KERN_SYSVIPC_SHMMAX: not yet supported */
65 /* 6*/ /* KERN_SYSVIPC_SHMMNI: not yet supported */
66 /* 7*/ /* KERN_SYSVIPC_SHMSEG: not yet supported */
67 /* 8*/ /* KERN_SYSVIPC_SHMMAXPGS: not yet supported */
68 /* 9*/ /* KERN_SYSVIPC_SHMUSEPHYS: not yet supported */
69 /* In addition, NetBSD has a number of dynamic nodes here. */
72 /* The CTL_KERN KERN_SYSVIPC node. */
73 static struct rmib_node kern_ipc_node =
74 RMIB_NODE(RMIB_RO, kern_ipc_table, "ipc", "SysV IPC options");
77 * Initialize the IPC server.
79 static int
80 sef_cb_init_fresh(int type __unused, sef_init_info_t * info __unused)
82 const int mib[] = { CTL_KERN, KERN_SYSVIPC };
83 int r;
86 * Register our own "kern.ipc" subtree with the MIB service.
88 * This call only returns local failures. Remote failures (in the MIB
89 * service) are silently ignored. So, we can safely panic on failure.
91 if ((r = rmib_register(mib, __arraycount(mib), &kern_ipc_node)) != OK)
92 panic("unable to register remote MIB tree: %d", r);
94 return OK;
98 * The service has received a signal.
100 static void
101 sef_cb_signal_handler(int signo)
104 /* Only check for termination signal, ignore anything else. */
105 if (signo != SIGTERM) return;
108 * Check if there are still IPC keys around. If not, we can safely
109 * exit immediately. Otherwise, warn the system administrator.
111 if (is_sem_nil() && is_shm_nil()) {
112 rmib_deregister(&kern_ipc_node);
114 sef_exit(0);
117 printf("IPC: exit with unclean state\n");
121 * Perform SEF initialization.
123 static void
124 sef_local_startup(void)
127 /* Register init callbacks. */
128 sef_setcb_init_fresh(sef_cb_init_fresh);
129 sef_setcb_init_restart(sef_cb_init_fresh);
131 /* Register signal callbacks. */
132 sef_setcb_signal_handler(sef_cb_signal_handler);
134 /* Let SEF perform startup. */
135 sef_startup();
139 * Update the process event subscription mask if necessary, after one of the
140 * modules has changed its subscription needs. This code is set up so that
141 * support for SysV IPC message queues can be added easily later.
143 static void
144 update_sub(unsigned int new_mask)
147 /* If the old and new mask are not both zero or nonzero, update. */
148 if (!event_mask != !new_mask) {
150 * Subscribe to PM process events, or unsubscribe. While it
151 * might be tempting to implement a system that subscribes to
152 * events only from processes that are actually blocked (or
153 * using the SysV IPC facilities at all), this would result in
154 * race conditions where subscription could happen "too late"
155 * for an ongoing signal delivery, causing the affected process
156 * to deadlock. Subscribing to events from any other call is
157 * safe however, and we exploit that to limit the kernel-level
158 * message passing overhead in the common case (which is that
159 * the IPC servier is not being used at all). After we have
160 * unsubscribed, we may still get a few leftover events for the
161 * previous subscription, and we must properly reply to those.
163 if (new_mask)
164 proceventmask(PROC_EVENT_EXIT | PROC_EVENT_SIGNAL);
165 else
166 proceventmask(0);
169 event_mask = new_mask;
173 * Update the process event subscription mask for the semaphore code.
175 void
176 update_sem_sub(int want_events)
178 unsigned int new_mask;
180 new_mask = event_mask & ~SEM_EVENTS;
181 if (want_events)
182 new_mask |= SEM_EVENTS;
184 update_sub(new_mask);
188 * PM sent us a process event message. Handle it, and reply.
190 static void
191 got_proc_event(message * m)
193 endpoint_t endpt;
194 int r, has_exited;
196 endpt = m->m_pm_lsys_proc_event.endpt;
197 has_exited = (m->m_pm_lsys_proc_event.event == PROC_EVENT_EXIT);
200 * Currently, only semaphore handling needs to know about processes
201 * being signaled and exiting.
203 if (event_mask & SEM_EVENTS)
204 sem_process_event(endpt, has_exited);
206 /* Echo the request as a reply back to PM. */
207 m->m_type = PROC_EVENT_REPLY;
208 if ((r = asynsend3(m->m_source, m, AMF_NOREPLY)) != OK)
209 printf("IPC: replying to PM process event failed (%d)\n", r);
213 * The System V IPC server.
216 main(int argc, char ** argv)
218 message m;
219 unsigned int call_index;
220 int r, ipc_status;
222 /* SEF local startup. */
223 env_setargs(argc, argv);
224 sef_local_startup();
226 /* The main message loop. */
227 for (;;) {
228 if ((r = sef_receive_status(ANY, &m, &ipc_status)) != OK)
229 panic("IPC: sef_receive_status failed: %d", r);
231 if (verbose)
232 printf("IPC: got %d from %d\n", m.m_type, m.m_source);
234 if (is_ipc_notify(ipc_status)) {
235 printf("IPC: ignoring notification from %d\n",
236 m.m_source);
237 continue;
240 /* Process event messages from PM are handled separately. */
241 if (m.m_source == PM_PROC_NR && m.m_type == PROC_EVENT) {
242 got_proc_event(&m);
244 continue;
247 /* Remote MIB messages from MIB are handled separately too. */
248 if (m.m_source == MIB_PROC_NR) {
249 rmib_process(&m, ipc_status);
251 continue;
254 /* Dispatch the request. */
255 call_index = (unsigned int)(m.m_type - IPC_BASE);
257 if (call_index < __arraycount(call_vec) &&
258 call_vec[call_index] != NULL) {
259 r = call_vec[call_index](&m);
260 } else
261 r = ENOSYS;
263 /* Send a reply, if needed. */
264 if (r != SUSPEND) {
265 if (verbose)
266 printf("IPC: call result %d\n", r);
268 m.m_type = r;
270 * Other fields may have been set by the handler
271 * function already.
274 if ((r = ipc_sendnb(m.m_source, &m)) != OK)
275 printf("IPC: send error %d\n", r);
278 /* XXX there must be a better way to do this! */
279 update_refcount_and_destroy();
282 /* NOTREACHED */
283 return 0;