8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libbc / libc / gen / common / plock.c
blobfe3d0699291f08993512b05e89f54b896e080980
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 1989 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * plock - lock "segments" in physical memory.
32 * Supports SVID-compatible plock, taking into account dynamically linked
33 * objects (such as shared libraries).
36 #include <sys/types.h>
37 #include <sys/mman.h>
38 #include <sys/lock.h>
39 #include <sys/time.h>
40 #include <sys/resource.h>
41 #include <machine/param.h>
42 #include <machine/vmparam.h>
43 #include <a.out.h>
44 #include <link.h>
45 #include <errno.h>
48 * Globals we reference.
50 extern struct link_dynamic _DYNAMIC;
51 extern int mlock();
52 extern int munlock();
53 extern caddr_t sbrk(); /* find end of data segment */
54 extern caddr_t etext; /* end of text segment */
57 * Module-scope variables.
59 static int page_size = 0; /* cached result of getpagesize() */
60 static int lock_state = 0; /* lock state */
61 static int state_pid = -1; /* pid to which state belongs */
64 * Local worker routine to lock text and data segments. Handles
65 * dynamically loaded objects. This routine is highly dependent
66 * on executable format and layout.
68 * Arguments:
69 * op: desired operation
70 * f: function to perform
72 static int
73 apply_lock(int op, int (*f)(caddr_t, u_int))
75 int e = 0; /* return value */
76 caddr_t a; /* address of operation */
77 u_int l; /* length of operation */
78 struct link_map *lmp; /* link map walker */
79 struct exec *eh; /* exec header */
82 * Operate on application segment first.
84 switch (op) {
85 case TXTLOCK:
86 a = (caddr_t)USRTEXT; /* note: old Sun-2 not handled */
87 l = (u_int)&etext - USRTEXT;
88 break;
89 case DATLOCK:
90 a = (caddr_t)(((int)&etext + (SEGSIZ - 1)) & ~(SEGSIZ - 1));
91 l = (u_int)(sbrk(0) - a);
92 break;
94 l = (l + (page_size - 1)) & (u_int)~(page_size - 1);
97 * Perform the operation -- if failure, return immediately.
99 if (e = (*f)(a, l))
100 return (e);
103 * If we're not a dynamically linked program, we are finished.
105 if (&_DYNAMIC == 0)
106 return (0);
109 * Find the list of dynamically linked objects. If we get
110 * dynamic linking formats we don't recognize, then punt.
112 switch (_DYNAMIC.ld_version) {
113 case 2:
114 #if defined(__sparc)
115 case 3:
116 #endif /* __sparc */
117 lmp = _DYNAMIC.ld_un.ld_2->ld_loaded;
118 break;
119 default:
120 return (0);
124 * Loop over all objects. Extract the addresses and lengths as
125 * required, and perform the appropriate operation.
128 while (lmp) {
129 eh = (struct exec *)lmp->lm_addr;
130 switch (op) {
131 case TXTLOCK:
132 a = (caddr_t)eh;
133 l = (u_int)eh->a_text;
134 break;
135 case DATLOCK:
136 a = (caddr_t)((u_int)eh + N_DATADDR(*eh) -
137 N_TXTADDR(*eh));
138 l = (u_int)eh->a_data + (u_int)eh->a_bss;
139 break;
141 l = (l + (page_size - 1)) & ~(page_size - 1);
142 if (e = (*f)(a, l))
143 return (e);
144 lmp = lmp->lm_next;
146 return (0);
150 * plock
152 * Argument:
153 * op: desired operation
156 plock(int op)
158 int e = 0; /* return value */
159 int pid; /* current pid */
160 caddr_t a1, a2; /* loop variables */
161 struct rlimit rl; /* resource limit */
164 * Initialize static caches.
166 if (page_size == 0)
167 page_size = getpagesize();
170 * Validate state of lock's. If parent has forked, then
171 * the lock state needs to be reset (children do not inherit
172 * memory locks, and thus do not inherit their state).
174 if ((pid = getpid()) != state_pid) {
175 lock_state = 0;
176 state_pid = pid;
180 * Dispatch on operation. Note: plock and its relatives depend
181 * upon "op" being bit encoded.
183 switch (op) {
186 * UNLOCK: remove all memory locks. Requires that some be set!
188 case UNLOCK:
189 if (lock_state == 0) {
190 errno = EINVAL;
191 return (-1);
193 if (e = munlockall())
194 return (-1);
195 else {
196 lock_state = 0;
197 return (0);
199 /*NOTREACHED*/
202 * TXTLOCK: locks text segments.
204 case TXTLOCK:
207 * If a text or process lock is already set, then fail.
209 if ((lock_state & TXTLOCK) || (lock_state & PROCLOCK)) {
210 errno = EINVAL;
211 return (-1);
215 * Try to apply the lock(s). If a failure occurs,
216 * back them out. On success, remember that a text
217 * lock was set.
219 if (e = apply_lock(op, mlock))
220 (void) apply_lock(op, munlock);
221 else
222 lock_state |= TXTLOCK;
223 return (e);
224 /*NOTREACHED*/
227 * DATLOCK: locks data segment(s), including the stack and all
228 * future growth in the address space.
230 case DATLOCK:
233 * If a data or process lock is already set, then fail.
235 if ((lock_state & DATLOCK) || (lock_state & PROCLOCK)) {
236 errno = EINVAL;
237 return (-1);
241 * Try to lock the data segments. On failure, back out
242 * the locks and return.
244 if (e = apply_lock(op, mlock)) {
245 (void) apply_lock(op, munlock);
246 return (-1);
250 * Try to lock the stack segment. Find out the extent
251 * and start of the stack (there should be a function for
252 * this!) and then iterate over the pages of the stack
253 * locking them. The stack *could* be sparely populated.
254 * Ignore lock failures resulting from the absence of a
255 * mapping.
257 (void) getrlimit(RLIMIT_STACK, &rl);
258 for (a1 = (caddr_t)USRSTACK - page_size;
259 a1 != (caddr_t)USRSTACK - rl.rlim_cur; a1 -= page_size)
260 if (e = mlock(a1, page_size)) {
261 if (errno == ENOMEM)
262 e = 0;
263 break;
267 * If we were successful in locking the stack, then
268 * try to set a lock for all future mappings.
270 if (!e)
271 e = mlockall(MCL_FUTURE);
274 * If failures have occurred, back out the locks
275 * and return failure.
277 if (e) {
278 e = errno;
279 (void) apply_lock(op, munlock);
280 for (a2 = (caddr_t)USRSTACK - page_size; a2 != a1;
281 a2 -= page_size)
282 (void) munlock(a2, page_size);
283 errno = e;
284 return (-1);
288 * Data, stack, and growth have been locked. Set state
289 * and return success.
291 lock_state |= DATLOCK;
292 return (0);
293 /*NOTREACHED*/
296 * PROCLOCK: lock everything, and all future things as well.
297 * There should be nothing locked when this is called.
299 case PROCLOCK:
300 if (lock_state) {
301 errno = EINVAL;
302 return (-1);
304 if (mlockall(MCL_CURRENT | MCL_FUTURE) == 0) {
305 lock_state |= PROCLOCK;
306 return (0);
307 } else
308 return (-1);
309 /*NOTREACHED*/
312 * Invalid operation.
314 default:
315 errno = EINVAL;
316 return (-1);
317 /*NOTREACHED*/