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 */ 21*5891Sraf 220Sstevel@tonic-gate /* 23*5891Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 29*5891Sraf #include "c_synonyms.h" 300Sstevel@tonic-gate #include "umem_base.h" 310Sstevel@tonic-gate #include "vmem_base.h" 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <signal.h> 340Sstevel@tonic-gate 350Sstevel@tonic-gate /*ARGSUSED*/ 360Sstevel@tonic-gate static void * 370Sstevel@tonic-gate umem_update_thread(void *arg) 380Sstevel@tonic-gate { 390Sstevel@tonic-gate struct timeval now; 400Sstevel@tonic-gate int in_update = 0; 410Sstevel@tonic-gate 420Sstevel@tonic-gate (void) mutex_lock(&umem_update_lock); 430Sstevel@tonic-gate 440Sstevel@tonic-gate ASSERT(umem_update_thr == thr_self()); 450Sstevel@tonic-gate ASSERT(umem_st_update_thr == 0); 460Sstevel@tonic-gate 470Sstevel@tonic-gate for (;;) { 480Sstevel@tonic-gate umem_process_updates(); 490Sstevel@tonic-gate 500Sstevel@tonic-gate if (in_update) { 510Sstevel@tonic-gate in_update = 0; 520Sstevel@tonic-gate /* 530Sstevel@tonic-gate * we wait until now to set the next update time 540Sstevel@tonic-gate * so that the updates are self-throttling 550Sstevel@tonic-gate */ 560Sstevel@tonic-gate (void) gettimeofday(&umem_update_next, NULL); 570Sstevel@tonic-gate umem_update_next.tv_sec += umem_reap_interval; 580Sstevel@tonic-gate } 590Sstevel@tonic-gate 600Sstevel@tonic-gate switch (umem_reaping) { 610Sstevel@tonic-gate case UMEM_REAP_DONE: 620Sstevel@tonic-gate case UMEM_REAP_ADDING: 630Sstevel@tonic-gate break; 640Sstevel@tonic-gate 650Sstevel@tonic-gate case UMEM_REAP_ACTIVE: 660Sstevel@tonic-gate umem_reap_next = gethrtime() + 670Sstevel@tonic-gate (hrtime_t)umem_reap_interval * NANOSEC; 680Sstevel@tonic-gate umem_reaping = UMEM_REAP_DONE; 690Sstevel@tonic-gate break; 700Sstevel@tonic-gate 710Sstevel@tonic-gate default: 720Sstevel@tonic-gate ASSERT(umem_reaping == UMEM_REAP_DONE || 730Sstevel@tonic-gate umem_reaping == UMEM_REAP_ADDING || 740Sstevel@tonic-gate umem_reaping == UMEM_REAP_ACTIVE); 750Sstevel@tonic-gate break; 760Sstevel@tonic-gate } 770Sstevel@tonic-gate 780Sstevel@tonic-gate (void) gettimeofday(&now, NULL); 790Sstevel@tonic-gate if (now.tv_sec > umem_update_next.tv_sec || 800Sstevel@tonic-gate (now.tv_sec == umem_update_next.tv_sec && 810Sstevel@tonic-gate now.tv_usec >= umem_update_next.tv_usec)) { 820Sstevel@tonic-gate /* 830Sstevel@tonic-gate * Time to run an update 840Sstevel@tonic-gate */ 850Sstevel@tonic-gate (void) mutex_unlock(&umem_update_lock); 860Sstevel@tonic-gate 870Sstevel@tonic-gate vmem_update(NULL); 880Sstevel@tonic-gate /* 890Sstevel@tonic-gate * umem_cache_update can use umem_add_update to 900Sstevel@tonic-gate * request further work. The update is not complete 910Sstevel@tonic-gate * until all such work is finished. 920Sstevel@tonic-gate */ 930Sstevel@tonic-gate umem_cache_applyall(umem_cache_update); 940Sstevel@tonic-gate 950Sstevel@tonic-gate (void) mutex_lock(&umem_update_lock); 960Sstevel@tonic-gate in_update = 1; 970Sstevel@tonic-gate continue; /* start processing immediately */ 980Sstevel@tonic-gate } 990Sstevel@tonic-gate 1000Sstevel@tonic-gate /* 1010Sstevel@tonic-gate * if there is no work to do, we wait until it is time for 1020Sstevel@tonic-gate * next update, or someone wakes us. 1030Sstevel@tonic-gate */ 1040Sstevel@tonic-gate if (umem_null_cache.cache_unext == &umem_null_cache) { 105*5891Sraf int cancel_state; 1060Sstevel@tonic-gate timespec_t abs_time; 1070Sstevel@tonic-gate abs_time.tv_sec = umem_update_next.tv_sec; 1080Sstevel@tonic-gate abs_time.tv_nsec = umem_update_next.tv_usec * 1000; 1090Sstevel@tonic-gate 110*5891Sraf (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 111*5891Sraf &cancel_state); 112*5891Sraf (void) cond_timedwait(&umem_update_cv, 1130Sstevel@tonic-gate &umem_update_lock, &abs_time); 114*5891Sraf (void) pthread_setcancelstate(cancel_state, NULL); 1150Sstevel@tonic-gate } 1160Sstevel@tonic-gate } 1174261Sbarts /* LINTED no return statement */ 1180Sstevel@tonic-gate } 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate int 1210Sstevel@tonic-gate umem_create_update_thread(void) 1220Sstevel@tonic-gate { 1230Sstevel@tonic-gate sigset_t sigmask, oldmask; 1244258Sbarts thread_t newthread; 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate ASSERT(MUTEX_HELD(&umem_update_lock)); 1270Sstevel@tonic-gate ASSERT(umem_update_thr == 0); 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate /* 1300Sstevel@tonic-gate * The update thread handles no signals 1310Sstevel@tonic-gate */ 1320Sstevel@tonic-gate (void) sigfillset(&sigmask); 1330Sstevel@tonic-gate (void) thr_sigsetmask(SIG_BLOCK, &sigmask, &oldmask); 1344258Sbarts 1354258Sbarts /* 1364258Sbarts * drop the umem_update_lock; we cannot hold locks acquired in 1374258Sbarts * pre-fork handler while calling thr_create or thr_continue(). 1384258Sbarts */ 1394258Sbarts 1404258Sbarts (void) mutex_unlock(&umem_update_lock); 1414258Sbarts 1420Sstevel@tonic-gate if (thr_create(NULL, NULL, umem_update_thread, NULL, 1434258Sbarts THR_BOUND | THR_DAEMON | THR_DETACHED | THR_SUSPENDED, 1444258Sbarts &newthread) == 0) { 1450Sstevel@tonic-gate (void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL); 1464258Sbarts 1474258Sbarts (void) mutex_lock(&umem_update_lock); 1484258Sbarts /* 1494258Sbarts * due to the locking in umem_reap(), only one thread can 1504258Sbarts * ever call umem_create_update_thread() at a time. This 1514258Sbarts * must be the case for this code to work. 1524258Sbarts */ 1534258Sbarts 1544258Sbarts ASSERT(umem_update_thr == 0); 1554258Sbarts umem_update_thr = newthread; 1564258Sbarts (void) mutex_unlock(&umem_update_lock); 1574258Sbarts (void) thr_continue(newthread); 1584258Sbarts (void) mutex_lock(&umem_update_lock); 1594258Sbarts 1600Sstevel@tonic-gate return (1); 1614258Sbarts } else { /* thr_create failed */ 1624258Sbarts (void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL); 1634258Sbarts (void) mutex_lock(&umem_update_lock); 1640Sstevel@tonic-gate } 1650Sstevel@tonic-gate return (0); 1660Sstevel@tonic-gate } 167