xref: /illumos-gate/usr/src/lib/libc/port/gen/plock.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * plock - lock "segments" in physical memory.
31  *
32  * Supports SVID-compatible plock, taking into account dynamically linked
33  * objects (such as shared libraries).
34  */
35 
36 #include "lint.h"
37 #include <mtlib.h>
38 #include <sys/types.h>
39 #include <sys/mman.h>
40 #include <sys/lock.h>
41 #include <errno.h>
42 #include <stddef.h>
43 #include <unistd.h>
44 #include <thread.h>
45 #include <synch.h>
46 
47 /*
48  * Module-scope variables.
49  */
50 static	int lock_state = 0;		/* lock state */
51 static	pid_t state_pid = -1;		/* pid to which state belongs */
52 static mutex_t plock_lock = DEFAULTMUTEX;
53 
54 /*
55  * plock
56  */
57 int
58 plock(int op)				/* desired operation */
59 {
60 	int 	e;			/* return value */
61 	pid_t	pid;			/* current pid */
62 
63 	lmutex_lock(&plock_lock);
64 
65 	/*
66 	 * Validate state of lock's.  If parent has forked, then
67 	 * the lock state needs to be reset (children do not inherit
68 	 * memory locks, and thus do not inherit their state).
69 	 */
70 	if ((pid = getpid()) != state_pid) {
71 		lock_state = 0;
72 		state_pid = pid;
73 	}
74 
75 	/*
76 	 * Dispatch on operation.  Note: plock and its relatives depend
77 	 * upon "op" being bit encoded.
78 	 */
79 	switch (op) {
80 
81 	/*
82 	 * UNLOCK: remove all memory locks.  Requires that some be set!
83 	 */
84 	case UNLOCK:
85 		if (lock_state == 0) {
86 			errno = EINVAL;
87 			lmutex_unlock(&plock_lock);
88 			return (-1);
89 		}
90 		e = munlockall();
91 		if (e) {
92 			lmutex_unlock(&plock_lock);
93 			return (-1);
94 		} else {
95 			lock_state = 0;
96 			lmutex_unlock(&plock_lock);
97 			return (0);
98 		}
99 		/*NOTREACHED*/
100 
101 	/*
102 	 * TXTLOCK: locks text segments.
103 	 */
104 	case TXTLOCK:
105 
106 		/*
107 		 * If a text or process lock is already set, then fail.
108 		 */
109 		if ((lock_state & TXTLOCK) || (lock_state & PROCLOCK)) {
110 			errno = EINVAL;
111 			lmutex_unlock(&plock_lock);
112 			return (-1);
113 		}
114 
115 		/*
116 		 * Try to apply the lock(s).  If a failure occurs,
117 		 * memcntl backs them out automatically.
118 		 */
119 		e = memcntl(NULL, 0, MC_LOCKAS, (caddr_t)MCL_CURRENT,
120 		    PROC_TEXT|PRIVATE, (int)NULL);
121 		if (!e)
122 			lock_state |= TXTLOCK;
123 		lmutex_unlock(&plock_lock);
124 		return (e);
125 		/*NOTREACHED*/
126 
127 	/*
128 	 * DATLOCK: locks data segment(s), including the stack and all
129 	 * future growth in the address space.
130 	 */
131 	case DATLOCK:
132 
133 		/*
134 		 * If a data or process lock is already set, then fail.
135 		 */
136 		if ((lock_state & DATLOCK) || (lock_state & PROCLOCK)) {
137 			errno = EINVAL;
138 			lmutex_unlock(&plock_lock);
139 			return (-1);
140 		}
141 
142 		/*
143 		 * Try to lock the data and stack segments.  On failure
144 		 * memcntl undoes the locks internally.
145 		 */
146 		e = memcntl(NULL, 0, MC_LOCKAS, (caddr_t)MCL_CURRENT,
147 		    PROC_DATA|PRIVATE, (int)NULL);
148 		if (e) {
149 			lmutex_unlock(&plock_lock);
150 			return (-1);
151 		}
152 
153 		/* try to set a lock for all future mappings. */
154 		e = mlockall(MCL_FUTURE);
155 
156 		/*
157 		 * If failures have occurred, back out the locks
158 		 * and return failure.
159 		 */
160 		if (e) {
161 			e = errno;
162 			(void) memcntl(NULL, 0, MC_UNLOCKAS,
163 			    (caddr_t)MCL_CURRENT, PROC_DATA|PRIVATE, (int)NULL);
164 			errno = e;
165 			lmutex_unlock(&plock_lock);
166 			return (-1);
167 		}
168 
169 		/*
170 		 * Data, stack, and growth have been locked.  Set state
171 		 * and return success.
172 		 */
173 		lock_state |= DATLOCK;
174 		lmutex_unlock(&plock_lock);
175 		return (0);
176 		/*NOTREACHED*/
177 
178 	/*
179 	 * PROCLOCK: lock everything, and all future things as well.
180 	 * There should be nothing locked when this is called.
181 	 */
182 	case PROCLOCK:
183 		if (lock_state) {
184 			errno = EINVAL;
185 			lmutex_unlock(&plock_lock);
186 			return (-1);
187 		}
188 		if (mlockall(MCL_CURRENT | MCL_FUTURE) == 0) {
189 			lock_state |= PROCLOCK;
190 			lmutex_unlock(&plock_lock);
191 			return (0);
192 		} else {
193 			lmutex_unlock(&plock_lock);
194 			return (-1);
195 		}
196 		/*NOTREACHED*/
197 
198 	/*
199 	 * Invalid operation.
200 	 */
201 	default:
202 		errno = EINVAL;
203 		lmutex_unlock(&plock_lock);
204 		return (-1);
205 		/*NOTREACHED*/
206 	}
207 }
208