/* * Copyright (c) 1996 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ /* * ldap_pvt_thread_sleep.c - allow a thread to sleep without putting * the whole process (e.g. pod under lwp) to sleep. * * Contains platform-specific code to allow this: * * Under non-preemptive threads packages like SunOS lwp, tsleep() adds * the thread to a list of sleepers. The lwp_scheduler process takes * care of resuming suspended threads. * * Under a fully-preemptive threads package, like Solaris threads, * tsleep just calls sleep(), and there is no scheduler thread. Life * is so much simpler... */ #include "portable.h" #include #include #include /* get sleep() */ #include "ldap_pvt_thread.h" #if !defined( HAVE_LWP ) /* * Here we assume we have fully preemptive threads and that sleep() * does the right thing. */ unsigned int ldap_pvt_thread_sleep( unsigned int interval ) { sleep( interval ); return 0; } #else unsigned int ldap_pvt_thread_sleep( unsigned int interval ) { thread_t mylwp; tl_t *t, *nt; time_t now; if ( lwp_self( &mylwp ) < 0 ) { return -1; } time( &now ); mon_enter( &sglob->tsl_mon ); if ( sglob->tsl_list != NULL ) { for ( t = sglob->tsl_list; t != NULL; t = t->tl_next ) { if ( SAMETHREAD( t->tl_tid, mylwp )) { /* We're already sleeping? */ t->tl_wake = now + interval; mon_exit( &sglob->tsl_mon ); lwp_suspend( mylwp ); return 0; } } } nt = (tl_t *) malloc( sizeof( tl_t )); nt->tl_next = sglob->tsl_list; nt->tl_wake = now + interval; nt->tl_tid = mylwp; sglob->tsl_list = nt; mon_exit( &sglob->tsl_mon ); lwp_suspend( mylwp ); return 0; } /* * The lwp_scheduler thread periodically checks to see if any threads * are due to be resumed. If there are, it resumes them. Otherwise, * it computes the lesser of ( 1 second ) or ( the minimum time until * a thread need to be resumed ) and puts itself to sleep for that amount * of time. */ void lwp_scheduler( int stackno ) { time_t now, min; struct timeval interval; tl_t *t; while ( !sglob->slurpd_shutdown ) { mon_enter( &sglob->tsl_mon ); time( &now ); min = 0L; if ( sglob->tsl_list != NULL ) { for ( t = sglob->tsl_list; t != NULL; t = t->tl_next ) { if (( t->tl_wake > 0L ) && ( t->tl_wake < now )) { lwp_resume( t->tl_tid ); t->tl_wake = 0L; } if (( t->tl_wake > now ) && ( t->tl_wake < min )) { min = t->tl_wake; } } } mon_exit( &sglob->tsl_mon ); interval.tv_usec = 0L; if ( min == 0L ) { interval.tv_sec = 1L; } else { interval.tv_sec = min; } lwp_sleep( &interval ); } mon_enter( &sglob->tsl_mon ); for ( t = sglob->tsl_list; t != NULL; t = t->tl_next ) { lwp_resume( t->tl_tid ); } mon_exit( &sglob->tsl_mon ); free_stack( stackno ); } #endif /* HAVE_LWP */