1 /* $NetBSD: thread.c,v 1.4 2025/09/05 21:16:29 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-2024 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.4 2025/09/05 21:16:29 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, *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 for ( i = 0; !BER_BVISNULL( &mt[ i ].rdn ); i++ ) { 129 static char buf[ BACKMONITOR_BUFSIZE ]; 130 int count = -1; 131 char *state = NULL; 132 struct berval bv = BER_BVNULL; 133 134 /* 135 * Max 136 */ 137 e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, 138 &mt[ i ].rdn, 139 mi->mi_oc_monitoredObject, NULL, NULL ); 140 if ( e == NULL ) { 141 Debug( LDAP_DEBUG_ANY, 142 "monitor_subsys_thread_init: " 143 "unable to create entry \"%s,%s\"\n", 144 mt[ i ].rdn.bv_val, 145 ms->mss_ndn.bv_val ); 146 return( -1 ); 147 } 148 149 /* NOTE: reference to the normalized DN of the entry, 150 * under the assumption it's not modified */ 151 dnRdn( &e->e_nname, &mt[ i ].nrdn ); 152 153 switch ( mt[ i ].param ) { 154 case LDAP_PVT_THREAD_POOL_PARAM_UNKNOWN: 155 break; 156 157 case LDAP_PVT_THREAD_POOL_PARAM_STATE: 158 if ( ldap_pvt_thread_pool_query( &connection_pool, 159 mt[ i ].param, (void *)&state ) == 0 ) 160 { 161 ber_str2bv( state, 0, 0, &bv ); 162 163 } else { 164 BER_BVSTR( &bv, "unknown" ); 165 } 166 break; 167 168 default: 169 /* NOTE: in case of error, it'll be set to -1 */ 170 (void)ldap_pvt_thread_pool_query( &connection_pool, 171 mt[ i ].param, (void *)&count ); 172 bv.bv_val = buf; 173 bv.bv_len = snprintf( buf, sizeof( buf ), "%d", count ); 174 break; 175 } 176 177 if ( !BER_BVISNULL( &bv ) ) { 178 attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo, &bv, NULL ); 179 } 180 181 if ( !BER_BVISNULL( &mt[ i ].desc ) ) { 182 attr_merge_normalize_one( e, 183 slap_schema.si_ad_description, 184 &mt[ i ].desc, NULL ); 185 } 186 187 mp = monitor_entrypriv_create(); 188 if ( mp == NULL ) { 189 return -1; 190 } 191 e->e_private = ( void * )mp; 192 mp->mp_info = ms; 193 mp->mp_flags = ms->mss_flags \ 194 | MONITOR_F_SUB | MONITOR_F_PERSISTENT; 195 196 if ( monitor_cache_add( mi, e, e_thread ) ) { 197 Debug( LDAP_DEBUG_ANY, 198 "monitor_subsys_thread_init: " 199 "unable to add entry \"%s,%s\"\n", 200 mt[ i ].rdn.bv_val, 201 ms->mss_dn.bv_val ); 202 return( -1 ); 203 } 204 } 205 206 monitor_cache_release( mi, e_thread ); 207 208 return( 0 ); 209 } 210 211 static int 212 monitor_subsys_thread_update( 213 Operation *op, 214 SlapReply *rs, 215 Entry *e ) 216 { 217 monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private; 218 Attribute *a; 219 BerVarray vals = NULL; 220 char buf[ BACKMONITOR_BUFSIZE ]; 221 struct berval rdn, bv; 222 int which, i; 223 struct re_s *re; 224 int count = -1; 225 char *state = NULL; 226 227 assert( mi != NULL ); 228 229 dnRdn( &e->e_nname, &rdn ); 230 231 for ( i = 0; !BER_BVISNULL( &mt[ i ].nrdn ); i++ ) { 232 if ( dn_match( &mt[ i ].nrdn, &rdn ) ) { 233 break; 234 } 235 } 236 237 which = i; 238 if ( BER_BVISNULL( &mt[ which ].nrdn ) ) { 239 return SLAP_CB_CONTINUE; 240 } 241 242 a = attr_find( e->e_attrs, mi->mi_ad_monitoredInfo ); 243 244 switch ( mt[ which ].param ) { 245 case LDAP_PVT_THREAD_POOL_PARAM_UNKNOWN: 246 switch ( mt[ which ].mt ) { 247 case MT_RUNQUEUE: 248 if ( a != NULL ) { 249 if ( a->a_nvals != a->a_vals ) { 250 ber_bvarray_free( a->a_nvals ); 251 } 252 ber_bvarray_free( a->a_vals ); 253 a->a_vals = NULL; 254 a->a_nvals = NULL; 255 a->a_numvals = 0; 256 } 257 258 i = 0; 259 bv.bv_val = buf; 260 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 261 LDAP_STAILQ_FOREACH( re, &slapd_rq.run_list, rnext ) { 262 bv.bv_len = snprintf( buf, sizeof( buf ), "{%d}%s(%s)", 263 i, re->tname, re->tspec ); 264 if ( bv.bv_len < sizeof( buf ) ) { 265 value_add_one( &vals, &bv ); 266 } 267 i++; 268 } 269 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 270 271 if ( vals ) { 272 attr_merge_normalize( e, mi->mi_ad_monitoredInfo, vals, NULL ); 273 ber_bvarray_free( vals ); 274 275 } else { 276 attr_delete( &e->e_attrs, mi->mi_ad_monitoredInfo ); 277 } 278 break; 279 280 case MT_TASKLIST: 281 if ( a != NULL ) { 282 if ( a->a_nvals != a->a_vals ) { 283 ber_bvarray_free( a->a_nvals ); 284 } 285 ber_bvarray_free( a->a_vals ); 286 a->a_vals = NULL; 287 a->a_nvals = NULL; 288 a->a_numvals = 0; 289 } 290 291 i = 0; 292 bv.bv_val = buf; 293 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 294 LDAP_STAILQ_FOREACH( re, &slapd_rq.task_list, tnext ) { 295 bv.bv_len = snprintf( buf, sizeof( buf ), "{%d}%s(%s)", 296 i, re->tname, re->tspec ); 297 if ( bv.bv_len < sizeof( buf ) ) { 298 value_add_one( &vals, &bv ); 299 } 300 i++; 301 } 302 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 303 304 if ( vals ) { 305 attr_merge_normalize( e, mi->mi_ad_monitoredInfo, vals, NULL ); 306 ber_bvarray_free( vals ); 307 308 } else { 309 attr_delete( &e->e_attrs, mi->mi_ad_monitoredInfo ); 310 } 311 break; 312 313 default: 314 assert( 0 ); 315 } 316 break; 317 318 case LDAP_PVT_THREAD_POOL_PARAM_STATE: 319 if ( a == NULL ) { 320 return rs->sr_err = LDAP_OTHER; 321 } 322 if ( ldap_pvt_thread_pool_query( &connection_pool, 323 mt[ i ].param, (void *)&state ) == 0 ) 324 { 325 ber_str2bv( state, 0, 0, &bv ); 326 ber_bvreplace( &a->a_vals[ 0 ], &bv ); 327 } 328 break; 329 330 default: 331 if ( a == NULL ) { 332 return rs->sr_err = LDAP_OTHER; 333 } 334 if ( ldap_pvt_thread_pool_query( &connection_pool, 335 mt[ i ].param, (void *)&count ) == 0 ) 336 { 337 bv.bv_val = buf; 338 bv.bv_len = snprintf( buf, sizeof( buf ), "%d", count ); 339 if ( bv.bv_len < sizeof( buf ) ) { 340 ber_bvreplace( &a->a_vals[ 0 ], &bv ); 341 } 342 } 343 break; 344 } 345 346 /* FIXME: touch modifyTimestamp? */ 347 348 return SLAP_CB_CONTINUE; 349 } 350