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