1/* thread.c - deal with thread subsystem */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 2001-2011 The OpenLDAP Foundation. 6 * Portions Copyright 2001-2003 Pierangelo Masarati. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted only as authorized by the OpenLDAP 11 * Public License. 12 * 13 * A copy of this license is available in file LICENSE in the 14 * top-level directory of the distribution or, alternatively, at 15 * <http://www.OpenLDAP.org/license.html>. 16 */ 17/* ACKNOWLEDGEMENTS: 18 * This work was initially developed by Pierangelo Masarati for inclusion 19 * in OpenLDAP Software. 20 */ 21 22#include "portable.h" 23 24#include <stdio.h> 25#include <ac/string.h> 26 27#include "slap.h" 28#include "back-monitor.h" 29 30#include <ldap_rq.h> 31 32#ifndef NO_THREADS 33typedef enum { 34 MT_UNKNOWN, 35 MT_RUNQUEUE, 36 MT_TASKLIST, 37 38 MT_LAST 39} monitor_thread_t; 40 41static struct { 42 struct berval rdn; 43 struct berval desc; 44 struct berval nrdn; 45 ldap_pvt_thread_pool_param_t param; 46 monitor_thread_t mt; 47} mt[] = { 48 { BER_BVC( "cn=Max" ), 49 BER_BVC("Maximum number of threads as configured"), 50 BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_MAX, MT_UNKNOWN }, 51 { BER_BVC( "cn=Max Pending" ), 52 BER_BVC("Maximum number of pending threads"), 53 BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_MAX_PENDING, MT_UNKNOWN }, 54 { BER_BVC( "cn=Open" ), 55 BER_BVC("Number of open threads"), 56 BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_OPEN, MT_UNKNOWN }, 57 { BER_BVC( "cn=Starting" ), 58 BER_BVC("Number of threads being started"), 59 BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_STARTING, MT_UNKNOWN }, 60 { BER_BVC( "cn=Active" ), 61 BER_BVC("Number of active threads"), 62 BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_ACTIVE, MT_UNKNOWN }, 63 { BER_BVC( "cn=Pending" ), 64 BER_BVC("Number of pending threads"), 65 BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_PENDING, MT_UNKNOWN }, 66 { BER_BVC( "cn=Backload" ), 67 BER_BVC("Number of active plus pending threads"), 68 BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_BACKLOAD, MT_UNKNOWN }, 69#if 0 /* not meaningful right now */ 70 { BER_BVC( "cn=Active Max" ), 71 BER_BVNULL, 72 BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_ACTIVE_MAX, MT_UNKNOWN }, 73 { BER_BVC( "cn=Pending Max" ), 74 BER_BVNULL, 75 BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_PENDING_MAX, MT_UNKNOWN }, 76 { BER_BVC( "cn=Backload Max" ), 77 BER_BVNULL, 78 BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_BACKLOAD_MAX,MT_UNKNOWN }, 79#endif 80 { BER_BVC( "cn=State" ), 81 BER_BVC("Thread pool state"), 82 BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_STATE, MT_UNKNOWN }, 83 84 { BER_BVC( "cn=Runqueue" ), 85 BER_BVC("Queue of running threads - besides those handling operations"), 86 BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_UNKNOWN, MT_RUNQUEUE }, 87 { BER_BVC( "cn=Tasklist" ), 88 BER_BVC("List of running plus standby threads - besides those handling operations"), 89 BER_BVNULL, LDAP_PVT_THREAD_POOL_PARAM_UNKNOWN, MT_TASKLIST }, 90 91 { BER_BVNULL } 92}; 93 94static int 95monitor_subsys_thread_update( 96 Operation *op, 97 SlapReply *rs, 98 Entry *e ); 99#endif /* ! NO_THREADS */ 100 101/* 102 * initializes log subentry 103 */ 104int 105monitor_subsys_thread_init( 106 BackendDB *be, 107 monitor_subsys_t *ms ) 108{ 109#ifndef NO_THREADS 110 monitor_info_t *mi; 111 monitor_entry_t *mp; 112 Entry *e, **ep, *e_thread; 113 int i; 114 115 ms->mss_update = monitor_subsys_thread_update; 116 117 mi = ( monitor_info_t * )be->be_private; 118 119 if ( monitor_cache_get( mi, &ms->mss_ndn, &e_thread ) ) { 120 Debug( LDAP_DEBUG_ANY, 121 "monitor_subsys_thread_init: unable to get entry \"%s\"\n", 122 ms->mss_dn.bv_val, 123 0, 0 ); 124 return( -1 ); 125 } 126 127 mp = ( monitor_entry_t * )e_thread->e_private; 128 mp->mp_children = NULL; 129 ep = &mp->mp_children; 130 131 for ( i = 0; !BER_BVISNULL( &mt[ i ].rdn ); i++ ) { 132 static char buf[ BACKMONITOR_BUFSIZE ]; 133 int count = -1; 134 char *state = NULL; 135 struct berval bv = BER_BVNULL; 136 137 /* 138 * Max 139 */ 140 e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, 141 &mt[ i ].rdn, 142 mi->mi_oc_monitoredObject, mi, NULL, NULL ); 143 if ( e == NULL ) { 144 Debug( LDAP_DEBUG_ANY, 145 "monitor_subsys_thread_init: " 146 "unable to create entry \"%s,%s\"\n", 147 mt[ i ].rdn.bv_val, 148 ms->mss_ndn.bv_val, 0 ); 149 return( -1 ); 150 } 151 152 /* NOTE: reference to the normalized DN of the entry, 153 * under the assumption it's not modified */ 154 dnRdn( &e->e_nname, &mt[ i ].nrdn ); 155 156 switch ( mt[ i ].param ) { 157 case LDAP_PVT_THREAD_POOL_PARAM_UNKNOWN: 158 break; 159 160 case LDAP_PVT_THREAD_POOL_PARAM_STATE: 161 if ( ldap_pvt_thread_pool_query( &connection_pool, 162 mt[ i ].param, (void *)&state ) == 0 ) 163 { 164 ber_str2bv( state, 0, 0, &bv ); 165 166 } else { 167 BER_BVSTR( &bv, "unknown" ); 168 } 169 break; 170 171 default: 172 /* NOTE: in case of error, it'll be set to -1 */ 173 (void)ldap_pvt_thread_pool_query( &connection_pool, 174 mt[ i ].param, (void *)&count ); 175 bv.bv_val = buf; 176 bv.bv_len = snprintf( buf, sizeof( buf ), "%d", count ); 177 break; 178 } 179 180 if ( !BER_BVISNULL( &bv ) ) { 181 attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo, &bv, NULL ); 182 } 183 184 if ( !BER_BVISNULL( &mt[ i ].desc ) ) { 185 attr_merge_normalize_one( e, 186 slap_schema.si_ad_description, 187 &mt[ i ].desc, NULL ); 188 } 189 190 mp = monitor_entrypriv_create(); 191 if ( mp == NULL ) { 192 return -1; 193 } 194 e->e_private = ( void * )mp; 195 mp->mp_info = ms; 196 mp->mp_flags = ms->mss_flags \ 197 | MONITOR_F_SUB | MONITOR_F_PERSISTENT; 198 199 if ( monitor_cache_add( mi, e ) ) { 200 Debug( LDAP_DEBUG_ANY, 201 "monitor_subsys_thread_init: " 202 "unable to add entry \"%s,%s\"\n", 203 mt[ i ].rdn.bv_val, 204 ms->mss_dn.bv_val, 0 ); 205 return( -1 ); 206 } 207 208 *ep = e; 209 ep = &mp->mp_next; 210 } 211 212 monitor_cache_release( mi, e_thread ); 213 214#endif /* ! NO_THREADS */ 215 return( 0 ); 216} 217 218#ifndef NO_THREADS 219static int 220monitor_subsys_thread_update( 221 Operation *op, 222 SlapReply *rs, 223 Entry *e ) 224{ 225 monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private; 226 Attribute *a; 227 BerVarray vals = NULL; 228 char buf[ BACKMONITOR_BUFSIZE ]; 229 struct berval rdn, bv; 230 int which, i; 231 struct re_s *re; 232 int count = -1; 233 char *state = NULL; 234 235 assert( mi != NULL ); 236 237 dnRdn( &e->e_nname, &rdn ); 238 239 for ( i = 0; !BER_BVISNULL( &mt[ i ].nrdn ); i++ ) { 240 if ( dn_match( &mt[ i ].nrdn, &rdn ) ) { 241 break; 242 } 243 } 244 245 which = i; 246 if ( BER_BVISNULL( &mt[ which ].nrdn ) ) { 247 return SLAP_CB_CONTINUE; 248 } 249 250 a = attr_find( e->e_attrs, mi->mi_ad_monitoredInfo ); 251 252 switch ( mt[ which ].param ) { 253 case LDAP_PVT_THREAD_POOL_PARAM_UNKNOWN: 254 switch ( mt[ which ].mt ) { 255 case MT_RUNQUEUE: 256 if ( a != NULL ) { 257 if ( a->a_nvals != a->a_vals ) { 258 ber_bvarray_free( a->a_nvals ); 259 } 260 ber_bvarray_free( a->a_vals ); 261 a->a_vals = NULL; 262 a->a_nvals = NULL; 263 a->a_numvals = 0; 264 } 265 266 i = 0; 267 bv.bv_val = buf; 268 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 269 LDAP_STAILQ_FOREACH( re, &slapd_rq.run_list, rnext ) { 270 bv.bv_len = snprintf( buf, sizeof( buf ), "{%d}%s(%s)", 271 i, re->tname, re->tspec ); 272 if ( bv.bv_len < sizeof( buf ) ) { 273 value_add_one( &vals, &bv ); 274 } 275 i++; 276 } 277 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 278 279 if ( vals ) { 280 attr_merge_normalize( e, mi->mi_ad_monitoredInfo, vals, NULL ); 281 ber_bvarray_free( vals ); 282 283 } else { 284 attr_delete( &e->e_attrs, mi->mi_ad_monitoredInfo ); 285 } 286 break; 287 288 case MT_TASKLIST: 289 if ( a != NULL ) { 290 if ( a->a_nvals != a->a_vals ) { 291 ber_bvarray_free( a->a_nvals ); 292 } 293 ber_bvarray_free( a->a_vals ); 294 a->a_vals = NULL; 295 a->a_nvals = NULL; 296 a->a_numvals = 0; 297 } 298 299 i = 0; 300 bv.bv_val = buf; 301 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 302 LDAP_STAILQ_FOREACH( re, &slapd_rq.task_list, tnext ) { 303 bv.bv_len = snprintf( buf, sizeof( buf ), "{%d}%s(%s)", 304 i, re->tname, re->tspec ); 305 if ( bv.bv_len < sizeof( buf ) ) { 306 value_add_one( &vals, &bv ); 307 } 308 i++; 309 } 310 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 311 312 if ( vals ) { 313 attr_merge_normalize( e, mi->mi_ad_monitoredInfo, vals, NULL ); 314 ber_bvarray_free( vals ); 315 316 } else { 317 attr_delete( &e->e_attrs, mi->mi_ad_monitoredInfo ); 318 } 319 break; 320 321 default: 322 assert( 0 ); 323 } 324 break; 325 326 case LDAP_PVT_THREAD_POOL_PARAM_STATE: 327 if ( a == NULL ) { 328 return rs->sr_err = LDAP_OTHER; 329 } 330 if ( ldap_pvt_thread_pool_query( &connection_pool, 331 mt[ i ].param, (void *)&state ) == 0 ) 332 { 333 ber_str2bv( state, 0, 0, &bv ); 334 ber_bvreplace( &a->a_vals[ 0 ], &bv ); 335 } 336 break; 337 338 default: 339 if ( a == NULL ) { 340 return rs->sr_err = LDAP_OTHER; 341 } 342 if ( ldap_pvt_thread_pool_query( &connection_pool, 343 mt[ i ].param, (void *)&count ) == 0 ) 344 { 345 bv.bv_val = buf; 346 bv.bv_len = snprintf( buf, sizeof( buf ), "%d", count ); 347 if ( bv.bv_len < sizeof( buf ) ) { 348 ber_bvreplace( &a->a_vals[ 0 ], &bv ); 349 } 350 } 351 break; 352 } 353 354 /* FIXME: touch modifyTimestamp? */ 355 356 return SLAP_CB_CONTINUE; 357} 358#endif /* ! NO_THREADS */ 359