3 #define SEM_EVENTS 0x01 /* semaphore code wants process events */
4 static unsigned int event_mask
= 0;
6 static int verbose
= 0;
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.
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)
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
);
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.
80 sef_cb_init_fresh(int type __unused
, sef_init_info_t
* info __unused
)
82 const int mib
[] = { CTL_KERN
, KERN_SYSVIPC
};
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
);
98 * The service has received a signal.
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
);
117 printf("IPC: exit with unclean state\n");
121 * Perform SEF initialization.
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. */
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.
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.
164 proceventmask(PROC_EVENT_EXIT
| PROC_EVENT_SIGNAL
);
169 event_mask
= new_mask
;
173 * Update the process event subscription mask for the semaphore code.
176 update_sem_sub(int want_events
)
178 unsigned int new_mask
;
180 new_mask
= event_mask
& ~SEM_EVENTS
;
182 new_mask
|= SEM_EVENTS
;
184 update_sub(new_mask
);
188 * PM sent us a process event message. Handle it, and reply.
191 got_proc_event(message
* m
)
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
)
219 unsigned int call_index
;
222 /* SEF local startup. */
223 env_setargs(argc
, argv
);
226 /* The main message loop. */
228 if ((r
= sef_receive_status(ANY
, &m
, &ipc_status
)) != OK
)
229 panic("IPC: sef_receive_status failed: %d", r
);
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",
240 /* Process event messages from PM are handled separately. */
241 if (m
.m_source
== PM_PROC_NR
&& m
.m_type
== PROC_EVENT
) {
247 /* Remote MIB messages from MIB are handled separately too. */
248 if (m
.m_source
== MIB_PROC_NR
) {
249 rmib_process(&m
, ipc_status
);
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
);
263 /* Send a reply, if needed. */
266 printf("IPC: call result %d\n", r
);
270 * Other fields may have been set by the handler
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();