mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-15 03:01:09 +08:00
159 lines
3.5 KiB
C
159 lines
3.5 KiB
C
/*
|
|
* 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.
|
|
*/
|
|
|
|
/*
|
|
* tsleep.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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ac/unistd.h> /* get sleep() */
|
|
|
|
#include "slurp.h"
|
|
#include "globals.h"
|
|
|
|
|
|
#if defined( HAVE_LWP )
|
|
|
|
int
|
|
tsleep(
|
|
time_t 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 );
|
|
}
|
|
|
|
|
|
/*
|
|
* Create the lwp_scheduler thread.
|
|
*/
|
|
void
|
|
start_lwp_scheduler( void )
|
|
{
|
|
thread_t tid;
|
|
stkalign_t *stack;
|
|
int stackno;
|
|
|
|
if (( stack = get_stack( &stackno )) == NULL ) {
|
|
return;
|
|
}
|
|
lwp_create( &tid, lwp_scheduler, MINPRIO, 0, stack, 1, stackno );
|
|
return;
|
|
}
|
|
|
|
|
|
#else /* !HAVE_LWP */
|
|
|
|
/*
|
|
* Here we assume we have fully preemptive threads, and that sleep()
|
|
* does the right thing.
|
|
*/
|
|
int
|
|
tsleep(
|
|
time_t interval
|
|
)
|
|
{
|
|
sleep( interval );
|
|
return 0;
|
|
}
|
|
#endif /* !HAVE_LWP */
|