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