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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
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.
13  *
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]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 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 #include "umem_base.h"
30 #include "vmem_base.h"
31 
32 #include <signal.h>
33 
34 /*
35  * we use the _ version, since we don't want to be cancelled.
36  */
37 extern int _cond_timedwait(cond_t *cv, mutex_t *mutex, const timespec_t *delay);
38 
39 /*ARGSUSED*/
40 static void *
41 umem_update_thread(void *arg)
42 {
43 	struct timeval now;
44 	int in_update = 0;
45 
46 	(void) mutex_lock(&umem_update_lock);
47 
48 	ASSERT(umem_update_thr == thr_self());
49 	ASSERT(umem_st_update_thr == 0);
50 
51 	for (;;) {
52 		umem_process_updates();
53 
54 		if (in_update) {
55 			in_update = 0;
56 			/*
57 			 * we wait until now to set the next update time
58 			 * so that the updates are self-throttling
59 			 */
60 			(void) gettimeofday(&umem_update_next, NULL);
61 			umem_update_next.tv_sec += umem_reap_interval;
62 		}
63 
64 		switch (umem_reaping) {
65 		case UMEM_REAP_DONE:
66 		case UMEM_REAP_ADDING:
67 			break;
68 
69 		case UMEM_REAP_ACTIVE:
70 			umem_reap_next = gethrtime() +
71 			    (hrtime_t)umem_reap_interval * NANOSEC;
72 			umem_reaping = UMEM_REAP_DONE;
73 			break;
74 
75 		default:
76 			ASSERT(umem_reaping == UMEM_REAP_DONE ||
77 			    umem_reaping == UMEM_REAP_ADDING ||
78 			    umem_reaping == UMEM_REAP_ACTIVE);
79 			break;
80 		}
81 
82 		(void) gettimeofday(&now, NULL);
83 		if (now.tv_sec > umem_update_next.tv_sec ||
84 		    (now.tv_sec == umem_update_next.tv_sec &&
85 		    now.tv_usec >= umem_update_next.tv_usec)) {
86 			/*
87 			 * Time to run an update
88 			 */
89 			(void) mutex_unlock(&umem_update_lock);
90 
91 			vmem_update(NULL);
92 			/*
93 			 * umem_cache_update can use umem_add_update to
94 			 * request further work.  The update is not complete
95 			 * until all such work is finished.
96 			 */
97 			umem_cache_applyall(umem_cache_update);
98 
99 			(void) mutex_lock(&umem_update_lock);
100 			in_update = 1;
101 			continue;	/* start processing immediately */
102 		}
103 
104 		/*
105 		 * if there is no work to do, we wait until it is time for
106 		 * next update, or someone wakes us.
107 		 */
108 		if (umem_null_cache.cache_unext == &umem_null_cache) {
109 			timespec_t abs_time;
110 			abs_time.tv_sec = umem_update_next.tv_sec;
111 			abs_time.tv_nsec = umem_update_next.tv_usec * 1000;
112 
113 			(void) _cond_timedwait(&umem_update_cv,
114 			    &umem_update_lock, &abs_time);
115 		}
116 	}
117 	/* LINTED no return statement */
118 }
119 
120 int
121 umem_create_update_thread(void)
122 {
123 	sigset_t sigmask, oldmask;
124 
125 	ASSERT(MUTEX_HELD(&umem_update_lock));
126 	ASSERT(umem_update_thr == 0);
127 
128 	/*
129 	 * The update thread handles no signals
130 	 */
131 	(void) sigfillset(&sigmask);
132 	(void) thr_sigsetmask(SIG_BLOCK, &sigmask, &oldmask);
133 	if (thr_create(NULL, NULL, umem_update_thread, NULL,
134 	    THR_BOUND | THR_DAEMON | THR_DETACHED, &umem_update_thr) == 0) {
135 		(void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL);
136 		return (1);
137 	}
138 	umem_update_thr = 0;
139 	(void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL);
140 	return (0);
141 }
142