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
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]
23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * File descriptor usage
32 * The number of processes that can be effectively managed is limited to less
33 * than half the number of descriptors available: one for each process's
34 * psinfo, the other its pagedata. When managing more processes, file
35 * descriptors are revoked as needed, in such a way as to maximize the
36 * distribution of descriptors to pagedata which will be useful in meeting a
37 * cap without paging out the process's working set, while retaining some
38 * benefit from caching psinfo descriptors, and leaving enough available for
39 * use by external consumers, such as are needed for project enumeration or
40 * configuration file reading.
42 * Revokable file descriptors are opened and associated with a callback
43 * function which can be invoked to revoke them later. pagedata and psinfo
44 * descriptors are differentiated for the purposes of preferring pagedata over
45 * psinfo, which effectively places the performance of rcapd behind the
46 * importance of making good page selections. The one exception is that one
47 * psinfo descriptor is guaranteed a place at any time, for the benefit of
48 * psinfo updates of a presently currently-scanned process. Descriptors are
49 * otherwise revoked in LIFO order.
52 #include <sys/types.h>
59 #include "rcapd_rfd.h"
62 static rfd_t
*tail
; /* tail of global list */
64 static int rfd_revoke_next(rfd_class_t
);
67 * Return the previous rfd_t of the given class, starting at (and including)
71 rfd_find_prev_class(rfd_t
*rfd
, rfd_class_t
class)
73 while (rfd
!= NULL
&& rfd
->rfd_class
!= class)
79 * Revoke and free the given rfd_t, returning as close does.
82 rfd_revoke_fd(rfd_t
*rfd
)
84 if (rfd
->rfd_revoke
!= NULL
)
86 return (rfd_close(rfd
->rfd_fd
));
90 * Revoke the next file descriptor according to the above constraints. Return
91 * nonzero if there are none to revoke.
94 rfd_revoke_next(rfd_class_t
class)
99 debug("nothing to revoke\n");
104 * RESERVED-clsas descriptors are all equivalent and may not be revoked
105 * to satisfy another request of the same clsas. rfd_reserve() uses
106 * this to reserve descriptors by first allocating, then closing, these
109 if (class != RFD_RESERVED
)
110 rfd
= rfd_find_prev_class(tail
, RFD_RESERVED
);
113 * Next try psinfo descriptors, leaving at least one open. Revoke the
114 * second-last psinfo descriptor, if possible.
117 rfd
= rfd_find_prev_class(tail
, RFD_PSINFO
);
119 rfd
= rfd
->rfd_prev_class
;
123 * Otherwise, revoke the last descriptor allocated, taking the same
124 * care as above that it is not reserved, if the reserved kind is
129 while (rfd
!= NULL
&& class == RFD_RESERVED
&& rfd
->rfd_class
==
135 return (rfd_revoke_fd(rfd
));
138 * Nothing but reserved-class descriptors are revocable, while a
139 * reserved- class descriptor was sought.
145 * Opens a file of the given class, which can later be revoked with the given
146 * callback. Returns as open does. The callback should reset any state that
147 * this caller establishes after the open, but should not close the descriptor,
148 * which will be done when the caller explicitly does so with rfd_close(), or
149 * the descriptor is revoked with rfd_revoke().
152 rfd_open(char *name
, int revoke_ok
, rfd_class_t
class,
153 void(*revoke
)(struct rfd
*), void *data
, int oflag
, mode_t mode
)
158 while ((fd
= open(name
, oflag
, mode
)) == -1 && (errno
== ENFILE
||
161 if (rfd_revoke_next(class) != 0)
169 * Create rfd_t and link into list.
171 rfd
= malloc(sizeof (*rfd
));
176 (void) bzero(rfd
, sizeof (*rfd
));
178 rfd
->rfd_class
= class;
179 rfd
->rfd_revoke
= revoke
;
180 rfd
->rfd_data
= data
;
182 rfd
->rfd_prev_class
= rfd_find_prev_class(tail
, class);
184 rfd
->rfd_prev_class
= tail
;
185 rfd
->rfd_prev
= tail
;
187 tail
->rfd_next
= rfd
;
195 * Close a given file descriptor, and return as close() does.
208 while (rfd
!= NULL
) {
209 rfdprev
= rfd
->rfd_prev
;
210 if (rfd
->rfd_fd
== fd
) {
211 if (rfd
->rfd_prev
!= NULL
)
212 rfd
->rfd_prev
->rfd_next
= rfd
->rfd_next
;
213 if (rfd
->rfd_next
!= NULL
)
214 rfd
->rfd_next
->rfd_prev
= rfd
->rfd_prev
;
216 tail
= rfd
->rfd_prev
;
217 for (nextclass
= rfd
->rfd_next
; nextclass
!= NULL
;
218 nextclass
= nextclass
->rfd_next
)
219 if (nextclass
->rfd_class
== rfd
->rfd_class
) {
220 nextclass
->rfd_prev_class
=
237 * Makes sure at least n descriptors are available. Returns nonzero if
248 for (i
= 0; i
< n
&& fd
>= 0; i
++) {
250 * rfd_open() will append as many RFD_RESERVED-clsas
251 * descriptors to the current tail as are requested, revoking
252 * non-RFD_RESERVED-class descriptors until nothing else can be
253 * revoked or the reservation is met.
255 fd
= rfd_open("/dev/null", 1, RFD_RESERVED
, NULL
, NULL
,
262 debug("couldn't allocate %d descriptors\n", n
);
264 while (otail
!= NULL
) {
265 rfdnext
= otail
->rfd_next
;
266 (void) rfd_close(otail
->rfd_fd
);