thread.c revision 1.1.1.10 1 /* $NetBSD: thread.c,v 1.1.1.10 2025/09/05 21:09:48 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.1.1.10 2025/09/05 21:09:48 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