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