From f2cc7e8a0ac4453435b54a4abb42a1d5abc03b3d Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Tue, 10 Mar 2009 00:42:10 +0000 Subject: [PATCH] ITS#5836, add writetimeout keyword for timing out hung writers --- servers/slapd/bconfig.c | 5 ++- servers/slapd/config.c | 1 + servers/slapd/connection.c | 17 ++++++++- servers/slapd/daemon.c | 70 +++++++++++++++++++++++++++----------- servers/slapd/proto-slap.h | 3 ++ servers/slapd/result.c | 2 +- 6 files changed, 76 insertions(+), 22 deletions(-) diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c index eeed0cdc49..7979dc57f5 100644 --- a/servers/slapd/bconfig.c +++ b/servers/slapd/bconfig.c @@ -706,6 +706,9 @@ static ConfigTable config_back_cf_table[] = { &config_updateref, "( OLcfgDbAt:0.13 NAME 'olcUpdateRef' " "EQUALITY caseIgnoreMatch " "SUP labeledURI )", NULL, NULL }, + { "writetimeout", "timeout", 2, 2, 0, ARG_INT, + &global_writetimeout, "( OLcfgGlAt:88 NAME 'olcWriteTimeout' " + "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, { NULL, NULL, 0, 0, 0, ARG_IGNORED, NULL, NULL, NULL, NULL } }; @@ -764,7 +767,7 @@ static ConfigOCs cf_ocs[] = { "olcTLSCACertificatePath $ olcTLSCertificateFile $ " "olcTLSCertificateKeyFile $ olcTLSCipherSuite $ olcTLSCRLCheck $ " "olcTLSRandFile $ olcTLSVerifyClient $ olcTLSDHParamFile $ " - "olcTLSCRLFile $ olcToolThreads $ " + "olcTLSCRLFile $ olcToolThreads $ olcWriteTimeout $ " "olcObjectIdentifier $ olcAttributeTypes $ olcObjectClasses $ " "olcDitContentRules $ olcLdapSyntaxes ) )", Cft_Global }, { "( OLcfgGlOc:2 " diff --git a/servers/slapd/config.c b/servers/slapd/config.c index 2dfa57f5e6..e6c138b3ac 100644 --- a/servers/slapd/config.c +++ b/servers/slapd/config.c @@ -62,6 +62,7 @@ slap_mask_t global_allows = 0; slap_mask_t global_disallows = 0; int global_gentlehup = 0; int global_idletimeout = 0; +int global_writetimeout = 0; char *global_host = NULL; char *global_realm = NULL; char *sasl_host = NULL; diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c index 969fcf1cc5..6781d2a34f 100644 --- a/servers/slapd/connection.c +++ b/servers/slapd/connection.c @@ -218,9 +218,12 @@ int connections_shutdown(void) */ int connections_timeout_idle(time_t now) { - int i = 0; + int i = 0, writers = 0; int connindex; Connection* c; + time_t old; + + old = slapd_get_writetime(); for( c = connection_first( &connindex ); c != NULL; @@ -240,9 +243,21 @@ int connections_timeout_idle(time_t now) connection_closing( c, "idletimeout" ); connection_close( c ); i++; + continue; + } + if ( c->c_writewaiter ) { + writers = 1; + if( difftime( c->c_activitytime+global_writetimeout, now) < 0 ) { + /* close it */ + connection_closing( c, "writetimeout" ); + connection_close( c ); + i++; + } } } connection_done( c ); + if ( !writers ) + slapd_clr_writetime( old ); return i; } diff --git a/servers/slapd/daemon.c b/servers/slapd/daemon.c index fe87e196a4..f9606c928e 100644 --- a/servers/slapd/daemon.c +++ b/servers/slapd/daemon.c @@ -86,6 +86,8 @@ static ber_socket_t wake_sds[2] ; static int emfile; +static time_t chk_writetime; + static volatile int waking; #ifdef NO_THREADS #define WAKE_LISTENER(w) do { \ @@ -954,6 +956,9 @@ slapd_set_write( ber_socket_t s, int wake ) SLAP_SOCK_SET_WRITE( s ); slap_daemon.sd_nwriters++; } + if (( wake & 2 ) && global_writetimeout ) { + chk_writetime = slap_get_time(); + } ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); WAKE_LISTENER(wake); @@ -987,6 +992,25 @@ slapd_set_read( ber_socket_t s, int wake ) WAKE_LISTENER(wake); } +time_t +slapd_get_writetime() +{ + time_t cur; + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + cur = chk_writetime; + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); + return cur; +} + +void +slapd_clr_writetime( time_t old ) +{ + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + if ( chk_writetime == old ) + chk_writetime = 0; + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); +} + static void slapd_close( ber_socket_t s ) { @@ -2033,24 +2057,12 @@ slapd_daemon_task( { int l; time_t last_idle_check = 0; - struct timeval idle; int ebadf = 0; #define SLAPD_IDLE_CHECK_LIMIT 4 if ( global_idletimeout > 0 ) { last_idle_check = slap_get_time(); - /* Set the select timeout. - * Don't just truncate, preserve the fractions of - * seconds to prevent sleeping for zero time. - */ - idle.tv_sec = global_idletimeout / SLAPD_IDLE_CHECK_LIMIT; - idle.tv_usec = global_idletimeout - \ - ( idle.tv_sec * SLAPD_IDLE_CHECK_LIMIT ); - idle.tv_usec *= 1000000 / SLAPD_IDLE_CHECK_LIMIT; - } else { - idle.tv_sec = 0; - idle.tv_usec = 0; } slapd_add( wake_sds[0], 0, NULL ); @@ -2155,14 +2167,34 @@ slapd_daemon_task( now = slap_get_time(); - if ( ( global_idletimeout > 0 ) && - difftime( last_idle_check + - global_idletimeout/SLAPD_IDLE_CHECK_LIMIT, now ) < 0 ) - { - connections_timeout_idle( now ); - last_idle_check = now; + if ( global_idletimeout > 0 || chk_writetime ) { + int check = 0; + /* Set the select timeout. + * Don't just truncate, preserve the fractions of + * seconds to prevent sleeping for zero time. + */ + if ( chk_writetime ) { + tv.tv_sec = global_writetimeout; + tv.tv_usec = global_writetimeout; + if ( difftime( chk_writetime, now ) < 0 ) + check = 2; + } else { + tv.tv_sec = global_idletimeout / SLAPD_IDLE_CHECK_LIMIT; + tv.tv_usec = global_idletimeout - \ + ( tv.tv_sec * SLAPD_IDLE_CHECK_LIMIT ); + tv.tv_usec *= 1000000 / SLAPD_IDLE_CHECK_LIMIT; + if ( difftime( last_idle_check + + global_idletimeout/SLAPD_IDLE_CHECK_LIMIT, now ) < 0 ) + check = 1; + } + if ( check ) { + connections_timeout_idle( now ); + last_idle_check = now; + } + } else { + tv.tv_sec = 0; + tv.tv_usec = 0; } - tv = idle; #ifdef SIGHUP if ( slapd_gentle_shutdown ) { diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 3b2899b68c..dcdcee98ba 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -842,6 +842,8 @@ LDAP_SLAPD_F (void) slapd_set_write LDAP_P((ber_socket_t s, int wake)); LDAP_SLAPD_F (void) slapd_clr_write LDAP_P((ber_socket_t s, int wake)); LDAP_SLAPD_F (void) slapd_set_read LDAP_P((ber_socket_t s, int wake)); LDAP_SLAPD_F (int) slapd_clr_read LDAP_P((ber_socket_t s, int wake)); +LDAP_SLAPD_F (void) slapd_clr_writetime LDAP_P((time_t old)); +LDAP_SLAPD_F (time_t) slapd_get_writetime LDAP_P((void)); LDAP_SLAPD_V (volatile sig_atomic_t) slapd_abrupt_shutdown; LDAP_SLAPD_V (volatile sig_atomic_t) slapd_shutdown; @@ -1930,6 +1932,7 @@ LDAP_SLAPD_V (const char) Versionstr[]; LDAP_SLAPD_V (int) global_gentlehup; LDAP_SLAPD_V (int) global_idletimeout; +LDAP_SLAPD_V (int) global_writetimeout; LDAP_SLAPD_V (char *) global_host; LDAP_SLAPD_V (char *) global_realm; LDAP_SLAPD_V (char *) sasl_host; diff --git a/servers/slapd/result.c b/servers/slapd/result.c index 0756260de0..30b79cc39c 100644 --- a/servers/slapd/result.c +++ b/servers/slapd/result.c @@ -210,7 +210,7 @@ static long send_ldap_ber( /* wait for socket to be write-ready */ ldap_pvt_thread_mutex_lock( &conn->c_write2_mutex ); conn->c_writewaiter = 1; - slapd_set_write( conn->c_sd, 1 ); + slapd_set_write( conn->c_sd, 2 ); ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex ); ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); -- 2.39.5