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
monitor_subsys_thread_init(BackendDB * be,monitor_subsys_t * ms)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
monitor_subsys_thread_update(Operation * op,SlapReply * rs,Entry * e)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