10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 54258Sbarts * Common Development and Distribution License (the "License"). 64258Sbarts * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 224258Sbarts * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include "umem_base.h" 290Sstevel@tonic-gate #include "vmem_base.h" 300Sstevel@tonic-gate 310Sstevel@tonic-gate #include <signal.h> 320Sstevel@tonic-gate 330Sstevel@tonic-gate /* 340Sstevel@tonic-gate * we use the _ version, since we don't want to be cancelled. 350Sstevel@tonic-gate */ 360Sstevel@tonic-gate extern int _cond_timedwait(cond_t *cv, mutex_t *mutex, const timespec_t *delay); 370Sstevel@tonic-gate 380Sstevel@tonic-gate /*ARGSUSED*/ 390Sstevel@tonic-gate static void * 400Sstevel@tonic-gate umem_update_thread(void *arg) 410Sstevel@tonic-gate { 420Sstevel@tonic-gate struct timeval now; 430Sstevel@tonic-gate int in_update = 0; 440Sstevel@tonic-gate 450Sstevel@tonic-gate (void) mutex_lock(&umem_update_lock); 460Sstevel@tonic-gate 470Sstevel@tonic-gate ASSERT(umem_update_thr == thr_self()); 480Sstevel@tonic-gate ASSERT(umem_st_update_thr == 0); 490Sstevel@tonic-gate 500Sstevel@tonic-gate for (;;) { 510Sstevel@tonic-gate umem_process_updates(); 520Sstevel@tonic-gate 530Sstevel@tonic-gate if (in_update) { 540Sstevel@tonic-gate in_update = 0; 550Sstevel@tonic-gate /* 560Sstevel@tonic-gate * we wait until now to set the next update time 570Sstevel@tonic-gate * so that the updates are self-throttling 580Sstevel@tonic-gate */ 590Sstevel@tonic-gate (void) gettimeofday(&umem_update_next, NULL); 600Sstevel@tonic-gate umem_update_next.tv_sec += umem_reap_interval; 610Sstevel@tonic-gate } 620Sstevel@tonic-gate 630Sstevel@tonic-gate switch (umem_reaping) { 640Sstevel@tonic-gate case UMEM_REAP_DONE: 650Sstevel@tonic-gate case UMEM_REAP_ADDING: 660Sstevel@tonic-gate break; 670Sstevel@tonic-gate 680Sstevel@tonic-gate case UMEM_REAP_ACTIVE: 690Sstevel@tonic-gate umem_reap_next = gethrtime() + 700Sstevel@tonic-gate (hrtime_t)umem_reap_interval * NANOSEC; 710Sstevel@tonic-gate umem_reaping = UMEM_REAP_DONE; 720Sstevel@tonic-gate break; 730Sstevel@tonic-gate 740Sstevel@tonic-gate default: 750Sstevel@tonic-gate ASSERT(umem_reaping == UMEM_REAP_DONE || 760Sstevel@tonic-gate umem_reaping == UMEM_REAP_ADDING || 770Sstevel@tonic-gate umem_reaping == UMEM_REAP_ACTIVE); 780Sstevel@tonic-gate break; 790Sstevel@tonic-gate } 800Sstevel@tonic-gate 810Sstevel@tonic-gate (void) gettimeofday(&now, NULL); 820Sstevel@tonic-gate if (now.tv_sec > umem_update_next.tv_sec || 830Sstevel@tonic-gate (now.tv_sec == umem_update_next.tv_sec && 840Sstevel@tonic-gate now.tv_usec >= umem_update_next.tv_usec)) { 850Sstevel@tonic-gate /* 860Sstevel@tonic-gate * Time to run an update 870Sstevel@tonic-gate */ 880Sstevel@tonic-gate (void) mutex_unlock(&umem_update_lock); 890Sstevel@tonic-gate 900Sstevel@tonic-gate vmem_update(NULL); 910Sstevel@tonic-gate /* 920Sstevel@tonic-gate * umem_cache_update can use umem_add_update to 930Sstevel@tonic-gate * request further work. The update is not complete 940Sstevel@tonic-gate * until all such work is finished. 950Sstevel@tonic-gate */ 960Sstevel@tonic-gate umem_cache_applyall(umem_cache_update); 970Sstevel@tonic-gate 980Sstevel@tonic-gate (void) mutex_lock(&umem_update_lock); 990Sstevel@tonic-gate in_update = 1; 1000Sstevel@tonic-gate continue; /* start processing immediately */ 1010Sstevel@tonic-gate } 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate /* 1040Sstevel@tonic-gate * if there is no work to do, we wait until it is time for 1050Sstevel@tonic-gate * next update, or someone wakes us. 1060Sstevel@tonic-gate */ 1070Sstevel@tonic-gate if (umem_null_cache.cache_unext == &umem_null_cache) { 1080Sstevel@tonic-gate timespec_t abs_time; 1090Sstevel@tonic-gate abs_time.tv_sec = umem_update_next.tv_sec; 1100Sstevel@tonic-gate abs_time.tv_nsec = umem_update_next.tv_usec * 1000; 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate (void) _cond_timedwait(&umem_update_cv, 1130Sstevel@tonic-gate &umem_update_lock, &abs_time); 1140Sstevel@tonic-gate } 1150Sstevel@tonic-gate } 116*4261Sbarts /* LINTED no return statement */ 1170Sstevel@tonic-gate } 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate int 1200Sstevel@tonic-gate umem_create_update_thread(void) 1210Sstevel@tonic-gate { 1220Sstevel@tonic-gate sigset_t sigmask, oldmask; 1234258Sbarts thread_t newthread; 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate ASSERT(MUTEX_HELD(&umem_update_lock)); 1260Sstevel@tonic-gate ASSERT(umem_update_thr == 0); 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate /* 1290Sstevel@tonic-gate * The update thread handles no signals 1300Sstevel@tonic-gate */ 1310Sstevel@tonic-gate (void) sigfillset(&sigmask); 1320Sstevel@tonic-gate (void) thr_sigsetmask(SIG_BLOCK, &sigmask, &oldmask); 1334258Sbarts 1344258Sbarts /* 1354258Sbarts * drop the umem_update_lock; we cannot hold locks acquired in 1364258Sbarts * pre-fork handler while calling thr_create or thr_continue(). 1374258Sbarts */ 1384258Sbarts 1394258Sbarts (void) mutex_unlock(&umem_update_lock); 1404258Sbarts 1410Sstevel@tonic-gate if (thr_create(NULL, NULL, umem_update_thread, NULL, 1424258Sbarts THR_BOUND | THR_DAEMON | THR_DETACHED | THR_SUSPENDED, 1434258Sbarts &newthread) == 0) { 1440Sstevel@tonic-gate (void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL); 1454258Sbarts 1464258Sbarts (void) mutex_lock(&umem_update_lock); 1474258Sbarts /* 1484258Sbarts * due to the locking in umem_reap(), only one thread can 1494258Sbarts * ever call umem_create_update_thread() at a time. This 1504258Sbarts * must be the case for this code to work. 1514258Sbarts */ 1524258Sbarts 1534258Sbarts ASSERT(umem_update_thr == 0); 1544258Sbarts umem_update_thr = newthread; 1554258Sbarts (void) mutex_unlock(&umem_update_lock); 1564258Sbarts (void) thr_continue(newthread); 1574258Sbarts (void) mutex_lock(&umem_update_lock); 1584258Sbarts 1590Sstevel@tonic-gate return (1); 1604258Sbarts } else { /* thr_create failed */ 1614258Sbarts (void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL); 1624258Sbarts (void) mutex_lock(&umem_update_lock); 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate return (0); 1650Sstevel@tonic-gate } 166