xref: /illumos-gate/usr/src/lib/libc/port/gen/plock.c (revision e86c3f00315e5838c0ec0b14f34b94c292085956)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * plock - lock "segments" in physical memory.
29  *
30  * Supports SVID-compatible plock, taking into account dynamically linked
31  * objects (such as shared libraries).
32  */
33 
34 #include "lint.h"
35 #include <mtlib.h>
36 #include <sys/types.h>
37 #include <sys/mman.h>
38 #include <sys/lock.h>
39 #include <errno.h>
40 #include <stddef.h>
41 #include <unistd.h>
42 #include <thread.h>
43 #include <synch.h>
44 
45 /*
46  * Module-scope variables.
47  */
48 static	int lock_state = 0;		/* lock state */
49 static	pid_t state_pid = -1;		/* pid to which state belongs */
50 static mutex_t plock_lock = DEFAULTMUTEX;
51 
52 /*
53  * plock
54  */
55 int
plock(int op)56 plock(int op)				/* desired operation */
57 {
58 	int 	e;			/* return value */
59 	pid_t	pid;			/* current pid */
60 
61 	lmutex_lock(&plock_lock);
62 
63 	/*
64 	 * Validate state of lock's.  If parent has forked, then
65 	 * the lock state needs to be reset (children do not inherit
66 	 * memory locks, and thus do not inherit their state).
67 	 */
68 	if ((pid = getpid()) != state_pid) {
69 		lock_state = 0;
70 		state_pid = pid;
71 	}
72 
73 	/*
74 	 * Dispatch on operation.  Note: plock and its relatives depend
75 	 * upon "op" being bit encoded.
76 	 */
77 	switch (op) {
78 
79 	/*
80 	 * UNLOCK: remove all memory locks.  Requires that some be set!
81 	 */
82 	case UNLOCK:
83 		if (lock_state == 0) {
84 			errno = EINVAL;
85 			lmutex_unlock(&plock_lock);
86 			return (-1);
87 		}
88 		e = munlockall();
89 		if (e) {
90 			lmutex_unlock(&plock_lock);
91 			return (-1);
92 		} else {
93 			lock_state = 0;
94 			lmutex_unlock(&plock_lock);
95 			return (0);
96 		}
97 		/*NOTREACHED*/
98 
99 	/*
100 	 * TXTLOCK: locks text segments.
101 	 */
102 	case TXTLOCK:
103 
104 		/*
105 		 * If a text or process lock is already set, then fail.
106 		 */
107 		if ((lock_state & TXTLOCK) || (lock_state & PROCLOCK)) {
108 			errno = EINVAL;
109 			lmutex_unlock(&plock_lock);
110 			return (-1);
111 		}
112 
113 		/*
114 		 * Try to apply the lock(s).  If a failure occurs,
115 		 * memcntl backs them out automatically.
116 		 */
117 		e = memcntl(NULL, 0, MC_LOCKAS, (caddr_t)MCL_CURRENT,
118 		    PROC_TEXT|PRIVATE, 0);
119 		if (!e)
120 			lock_state |= TXTLOCK;
121 		lmutex_unlock(&plock_lock);
122 		return (e);
123 		/*NOTREACHED*/
124 
125 	/*
126 	 * DATLOCK: locks data segment(s), including the stack and all
127 	 * future growth in the address space.
128 	 */
129 	case DATLOCK:
130 
131 		/*
132 		 * If a data or process lock is already set, then fail.
133 		 */
134 		if ((lock_state & DATLOCK) || (lock_state & PROCLOCK)) {
135 			errno = EINVAL;
136 			lmutex_unlock(&plock_lock);
137 			return (-1);
138 		}
139 
140 		/*
141 		 * Try to lock the data and stack segments.  On failure
142 		 * memcntl undoes the locks internally.
143 		 */
144 		e = memcntl(NULL, 0, MC_LOCKAS, (caddr_t)MCL_CURRENT,
145 		    PROC_DATA|PRIVATE, 0);
146 		if (e) {
147 			lmutex_unlock(&plock_lock);
148 			return (-1);
149 		}
150 
151 		/* try to set a lock for all future mappings. */
152 		e = mlockall(MCL_FUTURE);
153 
154 		/*
155 		 * If failures have occurred, back out the locks
156 		 * and return failure.
157 		 */
158 		if (e) {
159 			e = errno;
160 			(void) memcntl(NULL, 0, MC_UNLOCKAS,
161 			    (caddr_t)MCL_CURRENT, PROC_DATA|PRIVATE, 0);
162 			errno = e;
163 			lmutex_unlock(&plock_lock);
164 			return (-1);
165 		}
166 
167 		/*
168 		 * Data, stack, and growth have been locked.  Set state
169 		 * and return success.
170 		 */
171 		lock_state |= DATLOCK;
172 		lmutex_unlock(&plock_lock);
173 		return (0);
174 		/*NOTREACHED*/
175 
176 	/*
177 	 * PROCLOCK: lock everything, and all future things as well.
178 	 * There should be nothing locked when this is called.
179 	 */
180 	case PROCLOCK:
181 		if (lock_state) {
182 			errno = EINVAL;
183 			lmutex_unlock(&plock_lock);
184 			return (-1);
185 		}
186 		if (mlockall(MCL_CURRENT | MCL_FUTURE) == 0) {
187 			lock_state |= PROCLOCK;
188 			lmutex_unlock(&plock_lock);
189 			return (0);
190 		} else {
191 			lmutex_unlock(&plock_lock);
192 			return (-1);
193 		}
194 		/*NOTREACHED*/
195 
196 	/*
197 	 * Invalid operation.
198 	 */
199 	default:
200 		errno = EINVAL;
201 		lmutex_unlock(&plock_lock);
202 		return (-1);
203 		/*NOTREACHED*/
204 	}
205 }
206