xref: /dflybsd-src/sys/kern/kern_ktr.c (revision fda7d3889b1114d34ad3a52a7257a2b80fe24e4c)
1 /*
2  * Copyright (c) 2005 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 /*
35  * The following copyright applies to the DDB command code:
36  *
37  * Copyright (c) 2000 John Baldwin <jhb@FreeBSD.org>
38  * All rights reserved.
39  *
40  * Redistribution and use in source and binary forms, with or without
41  * modification, are permitted provided that the following conditions
42  * are met:
43  * 1. Redistributions of source code must retain the above copyright
44  *    notice, this list of conditions and the following disclaimer.
45  * 2. Redistributions in binary form must reproduce the above copyright
46  *    notice, this list of conditions and the following disclaimer in the
47  *    documentation and/or other materials provided with the distribution.
48  * 3. Neither the name of the author nor the names of any co-contributors
49  *    may be used to endorse or promote products derived from this software
50  *    without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62  * SUCH DAMAGE.
63  */
64 
65 /*
66  * Kernel tracepoint facility.
67  */
68 
69 #include "opt_ddb.h"
70 #include "opt_ktr.h"
71 
72 #include <sys/param.h>
73 #include <sys/cons.h>
74 #include <sys/kernel.h>
75 #include <sys/libkern.h>
76 #include <sys/proc.h>
77 #include <sys/sysctl.h>
78 #include <sys/ktr.h>
79 #include <sys/systm.h>
80 #include <sys/time.h>
81 #include <sys/malloc.h>
82 #include <sys/spinlock.h>
83 #include <sys/thread2.h>
84 #include <sys/spinlock2.h>
85 #include <sys/ctype.h>
86 
87 #include <machine/cpu.h>
88 #include <machine/cpufunc.h>
89 #include <machine/specialreg.h>
90 #include <machine/md_var.h>
91 
92 #include <ddb/ddb.h>
93 
94 #ifndef KTR_ENTRIES
95 #define	KTR_ENTRIES		2048
96 #elif (KTR_ENTRIES & KTR_ENTRIES - 1)
97 #error KTR_ENTRIES must be a power of two
98 #endif
99 #define KTR_ENTRIES_MASK	(KTR_ENTRIES - 1)
100 
101 /*
102  * test logging support.  When ktr_testlogcnt is non-zero each synchronization
103  * interrupt will issue six back-to-back ktr logging messages on cpu 0
104  * so the user can determine KTR logging overheads.
105  */
106 #if !defined(KTR_TESTLOG)
107 #define KTR_TESTLOG	KTR_ALL
108 #endif
109 KTR_INFO_MASTER(testlog);
110 #if KTR_TESTLOG
111 KTR_INFO(KTR_TESTLOG, testlog, test1, 0, "test1 %d %d %d %d", int dummy1, int dummy2, int dummy3, int dummy4);
112 KTR_INFO(KTR_TESTLOG, testlog, test2, 1, "test2 %d %d %d %d", int dummy1, int dummy2, int dummy3, int dummy4);
113 KTR_INFO(KTR_TESTLOG, testlog, test3, 2, "test3 %d %d %d %d", int dummy1, int dummy2, int dummy3, int dummy4);
114 KTR_INFO(KTR_TESTLOG, testlog, test4, 3, "test4");
115 KTR_INFO(KTR_TESTLOG, testlog, test5, 4, "test5");
116 KTR_INFO(KTR_TESTLOG, testlog, test6, 5, "test6");
117 KTR_INFO(KTR_TESTLOG, testlog, pingpong, 6, "pingpong");
118 KTR_INFO(KTR_TESTLOG, testlog, pipeline, 7, "pipeline");
119 KTR_INFO(KTR_TESTLOG, testlog, crit_beg, 8, "crit_beg");
120 KTR_INFO(KTR_TESTLOG, testlog, crit_end, 9, "crit_end");
121 KTR_INFO(KTR_TESTLOG, testlog, spin_beg, 10, "spin_beg");
122 KTR_INFO(KTR_TESTLOG, testlog, spin_end, 11, "spin_end");
123 #define logtest(name)	KTR_LOG(testlog_ ## name, 0, 0, 0, 0)
124 #define logtest_noargs(name)	KTR_LOG(testlog_ ## name)
125 #endif
126 
127 MALLOC_DEFINE(M_KTR, "ktr", "ktr buffers");
128 
129 SYSCTL_NODE(_debug, OID_AUTO, ktr, CTLFLAG_RW, 0, "ktr");
130 
131 int		ktr_entries = KTR_ENTRIES;
132 SYSCTL_INT(_debug_ktr, OID_AUTO, entries, CTLFLAG_RD, &ktr_entries, 0,
133     "Size of the event buffer");
134 
135 int		ktr_version = KTR_VERSION;
136 SYSCTL_INT(_debug_ktr, OID_AUTO, version, CTLFLAG_RD, &ktr_version, 0, "");
137 
138 static int	ktr_stacktrace = 1;
139 SYSCTL_INT(_debug_ktr, OID_AUTO, stacktrace, CTLFLAG_RD, &ktr_stacktrace, 0, "");
140 
141 static int	ktr_resynchronize = 0;
142 SYSCTL_INT(_debug_ktr, OID_AUTO, resynchronize, CTLFLAG_RW,
143     &ktr_resynchronize, 0, "Resynchronize TSC 10 times a second");
144 
145 #if KTR_TESTLOG
146 static int	ktr_testlogcnt = 0;
147 SYSCTL_INT(_debug_ktr, OID_AUTO, testlogcnt, CTLFLAG_RW, &ktr_testlogcnt, 0, "");
148 static int	ktr_testipicnt = 0;
149 static int	ktr_testipicnt_remainder;
150 SYSCTL_INT(_debug_ktr, OID_AUTO, testipicnt, CTLFLAG_RW, &ktr_testipicnt, 0, "");
151 static int	ktr_testcritcnt = 0;
152 SYSCTL_INT(_debug_ktr, OID_AUTO, testcritcnt, CTLFLAG_RW, &ktr_testcritcnt, 0, "");
153 static int	ktr_testspincnt = 0;
154 SYSCTL_INT(_debug_ktr, OID_AUTO, testspincnt, CTLFLAG_RW, &ktr_testspincnt, 0, "");
155 #endif
156 
157 /*
158  * Give cpu0 a static buffer so the tracepoint facility can be used during
159  * early boot (note however that we still use a critical section, XXX).
160  */
161 static struct	ktr_entry ktr_buf0[KTR_ENTRIES];
162 
163 struct ktr_cpu ktr_cpu[MAXCPU] = {
164 	{ .core.ktr_buf = &ktr_buf0[0] }
165 };
166 
167 static int64_t	ktr_sync_tsc;
168 struct callout	ktr_resync_callout;
169 
170 #ifdef KTR_VERBOSE
171 int	ktr_verbose = KTR_VERBOSE;
172 TUNABLE_INT("debug.ktr.verbose", &ktr_verbose);
173 SYSCTL_INT(_debug_ktr, OID_AUTO, verbose, CTLFLAG_RW, &ktr_verbose, 0,
174     "Log events to the console as well");
175 #endif
176 
177 static void ktr_resync_callback(void *dummy __unused);
178 
179 extern int64_t tsc_offsets[];
180 
181 static void
182 ktr_sysinit(void *dummy)
183 {
184 	struct ktr_cpu_core *kcpu;
185 	int i;
186 
187 	for(i = 1; i < ncpus; ++i) {
188 		kcpu = &ktr_cpu[i].core;
189 		kcpu->ktr_buf = kmalloc(KTR_ENTRIES * sizeof(struct ktr_entry),
190 					M_KTR, M_WAITOK | M_ZERO);
191 	}
192 	callout_init_mp(&ktr_resync_callout);
193 	callout_reset(&ktr_resync_callout, hz / 10, ktr_resync_callback, NULL);
194 }
195 SYSINIT(ktr_sysinit, SI_BOOT2_KLD, SI_ORDER_ANY, ktr_sysinit, NULL);
196 
197 /*
198  * Try to resynchronize the TSC's for all cpus.  This is really, really nasty.
199  * We have to send an IPIQ message to all remote cpus, wait until they
200  * get into their IPIQ processing code loop, then do an even stricter hard
201  * loop to get the cpus as close to synchronized as we can to get the most
202  * accurate reading.
203  *
204  * This callback occurs on cpu0.
205  */
206 #if KTR_TESTLOG
207 static void ktr_pingpong_remote(void *dummy);
208 static void ktr_pipeline_remote(void *dummy);
209 #endif
210 
211 #ifdef _RDTSC_SUPPORTED_
212 
213 static void ktr_resync_remote(void *dummy);
214 extern cpumask_t smp_active_mask;
215 
216 /*
217  * We use a callout callback instead of a systimer because we cannot afford
218  * to preempt anyone to do this, or we might deadlock a spin-lock or
219  * serializer between two cpus.
220  */
221 static
222 void
223 ktr_resync_callback(void *dummy __unused)
224 {
225 	struct lwkt_cpusync cs;
226 #if KTR_TESTLOG
227 	int count;
228 #endif
229 
230 	KKASSERT(mycpu->gd_cpuid == 0);
231 
232 #if KTR_TESTLOG
233 	/*
234 	 * Test logging
235 	 */
236 	if (ktr_testlogcnt) {
237 		--ktr_testlogcnt;
238 		cpu_disable_intr();
239 		logtest(test1);
240 		logtest(test2);
241 		logtest(test3);
242 		logtest_noargs(test4);
243 		logtest_noargs(test5);
244 		logtest_noargs(test6);
245 		cpu_enable_intr();
246 	}
247 
248 	/*
249 	 * Test IPI messaging
250 	 */
251 	if (ktr_testipicnt && ktr_testipicnt_remainder == 0 && ncpus > 1) {
252 		ktr_testipicnt_remainder = ktr_testipicnt;
253 		ktr_testipicnt = 0;
254 		lwkt_send_ipiq_bycpu(1, ktr_pingpong_remote, NULL);
255 	}
256 
257 	/*
258 	 * Test critical sections
259 	 */
260 	if (ktr_testcritcnt) {
261 		crit_enter();
262 		crit_exit();
263 		logtest_noargs(crit_beg);
264 		for (count = ktr_testcritcnt; count; --count) {
265 			crit_enter();
266 			crit_exit();
267 		}
268 		logtest_noargs(crit_end);
269 		ktr_testcritcnt = 0;
270 	}
271 
272 	/*
273 	 * Test spinlock sections
274 	 */
275 	if (ktr_testspincnt) {
276 		struct spinlock spin;
277 
278 		spin_init(&spin);
279 		spin_lock(&spin);
280 		spin_unlock(&spin);
281 		logtest_noargs(spin_beg);
282 		for (count = ktr_testspincnt; count; --count) {
283 			spin_lock(&spin);
284 			spin_unlock(&spin);
285 		}
286 		logtest_noargs(spin_end);
287 		ktr_testspincnt = 0;
288 	}
289 #endif
290 
291 	/*
292 	 * Resynchronize the TSC
293 	 */
294 	if (ktr_resynchronize == 0)
295 		goto done;
296 	if ((cpu_feature & CPUID_TSC) == 0)
297 		return;
298 
299 	crit_enter();
300 	lwkt_cpusync_init(&cs, smp_active_mask, ktr_resync_remote,
301 			  (void *)(intptr_t)mycpu->gd_cpuid);
302 	lwkt_cpusync_interlock(&cs);
303 	ktr_sync_tsc = rdtsc();
304 	lwkt_cpusync_deinterlock(&cs);
305 	crit_exit();
306 done:
307 	callout_reset(&ktr_resync_callout, hz / 10, ktr_resync_callback, NULL);
308 }
309 
310 /*
311  * The remote-end of the KTR synchronization protocol runs on all cpus.
312  * The one we run on the controlling cpu updates its tsc continuously
313  * until the others have finished syncing (theoretically), but we don't
314  * loop forever.
315  *
316  * This is a bit ad-hoc but we need to avoid livelocking inside an IPI
317  * callback.  rdtsc() is a synchronizing instruction (I think).
318  */
319 static void
320 ktr_resync_remote(void *arg)
321 {
322 	globaldata_t gd = mycpu;
323 	int64_t delta;
324 	int i;
325 
326 	if (gd->gd_cpuid == (int)(intptr_t)arg) {
327 		for (i = 0; i < 2000; ++i)
328 			ktr_sync_tsc = rdtsc();
329 	} else {
330 		delta = rdtsc() - ktr_sync_tsc;
331 		if (tsc_offsets[gd->gd_cpuid] == 0)
332 			tsc_offsets[gd->gd_cpuid] = delta;
333 		tsc_offsets[gd->gd_cpuid] =
334 			(tsc_offsets[gd->gd_cpuid] * 7 + delta) / 8;
335 	}
336 }
337 
338 #if KTR_TESTLOG
339 
340 static
341 void
342 ktr_pingpong_remote(void *dummy __unused)
343 {
344 	int other_cpu;
345 
346 	logtest_noargs(pingpong);
347 	other_cpu = 1 - mycpu->gd_cpuid;
348 	if (ktr_testipicnt_remainder) {
349 		--ktr_testipicnt_remainder;
350 		lwkt_send_ipiq_bycpu(other_cpu, ktr_pingpong_remote, NULL);
351 	} else {
352 		lwkt_send_ipiq_bycpu(other_cpu, ktr_pipeline_remote, NULL);
353 		lwkt_send_ipiq_bycpu(other_cpu, ktr_pipeline_remote, NULL);
354 		lwkt_send_ipiq_bycpu(other_cpu, ktr_pipeline_remote, NULL);
355 		lwkt_send_ipiq_bycpu(other_cpu, ktr_pipeline_remote, NULL);
356 		lwkt_send_ipiq_bycpu(other_cpu, ktr_pipeline_remote, NULL);
357 	}
358 }
359 
360 static
361 void
362 ktr_pipeline_remote(void *dummy __unused)
363 {
364 	logtest_noargs(pipeline);
365 }
366 
367 #endif
368 
369 #else	/* !_RDTSC_SUPPORTED_ */
370 
371 /*
372  * The resync callback for UP doesn't do anything other then run the test
373  * log messages.  If test logging is not enabled, don't bother resetting
374  * the callout.
375  */
376 static
377 void
378 ktr_resync_callback(void *dummy __unused)
379 {
380 #if KTR_TESTLOG
381 	/*
382 	 * Test logging
383 	 */
384 	if (ktr_testlogcnt) {
385 		--ktr_testlogcnt;
386 		cpu_disable_intr();
387 		logtest(test1);
388 		logtest(test2);
389 		logtest(test3);
390 		logtest_noargs(test4);
391 		logtest_noargs(test5);
392 		logtest_noargs(test6);
393 		cpu_enable_intr();
394 	}
395 	callout_reset(&ktr_resync_callout, hz / 10, ktr_resync_callback, NULL);
396 #endif
397 }
398 
399 #endif
400 
401 /*
402  * Setup the next empty slot and return it to the caller to store the data
403  * directly.
404  */
405 struct ktr_entry *
406 ktr_begin_write_entry(struct ktr_info *info, const char *file, int line)
407 {
408 	struct ktr_cpu_core *kcpu;
409 	struct ktr_entry *entry;
410 	int cpu;
411 
412 	cpu = mycpu->gd_cpuid;
413 	kcpu = &ktr_cpu[cpu].core;
414 	if (panicstr)			/* stop logging during panic */
415 		return NULL;
416 	if (kcpu->ktr_buf == NULL)	/* too early in boot */
417 		return NULL;
418 
419 	crit_enter();
420 	entry = kcpu->ktr_buf + (kcpu->ktr_idx & KTR_ENTRIES_MASK);
421 	++kcpu->ktr_idx;
422 #ifdef _RDTSC_SUPPORTED_
423 	if (cpu_feature & CPUID_TSC) {
424 		entry->ktr_timestamp = rdtsc() - tsc_offsets[cpu];
425 	} else
426 #endif
427 	{
428 		entry->ktr_timestamp = get_approximate_time_t();
429 	}
430 	entry->ktr_info = info;
431 	entry->ktr_file = file;
432 	entry->ktr_line = line;
433 	crit_exit();
434 	return entry;
435 }
436 
437 int
438 ktr_finish_write_entry(struct ktr_info *info, struct ktr_entry *entry)
439 {
440 	if (ktr_stacktrace)
441 		cpu_ktr_caller(entry);
442 #ifdef KTR_VERBOSE
443 	if (ktr_verbose && info->kf_format) {
444 		kprintf("cpu%d ", mycpu->gd_cpuid);
445 		if (ktr_verbose > 1) {
446 			kprintf("%s.%d\t", entry->ktr_file, entry->ktr_line);
447 		}
448 		return !0;
449 	}
450 #endif
451 	return 0;
452 }
453 
454 #ifdef DDB
455 
456 #define	NUM_LINES_PER_PAGE	19
457 
458 struct tstate {
459 	int	cur;
460 	int	first;
461 };
462 
463 static	int db_ktr_verbose;
464 static	int db_mach_vtrace(int cpu, struct ktr_entry *kp, int idx);
465 
466 DB_SHOW_COMMAND(ktr, db_ktr_all)
467 {
468 	struct ktr_cpu_core *kcpu;
469 	int a_flag = 0;
470 	int c;
471 	int nl = 0;
472 	int i;
473 	struct tstate tstate[MAXCPU];
474 	int printcpu = -1;
475 
476 	for(i = 0; i < ncpus; i++) {
477 		kcpu = &ktr_cpu[i].core;
478 		tstate[i].first = -1;
479 		tstate[i].cur = (kcpu->ktr_idx - 1) & KTR_ENTRIES_MASK;
480 	}
481 	db_ktr_verbose = 0;
482 	while ((c = *(modif++)) != '\0') {
483 		if (c == 'v') {
484 			db_ktr_verbose = 1;
485 		}
486 		else if (c == 'a') {
487 			a_flag = 1;
488 		}
489 		else if (c == 'c') {
490 			printcpu = 0;
491 			while ((c = *(modif++)) != '\0') {
492 				if (isdigit(c)) {
493 					printcpu *= 10;
494 					printcpu += c - '0';
495 				}
496 				else {
497 					modif++;
498 					break;
499 				}
500 			}
501 			modif--;
502 		}
503 	}
504 	if (printcpu > ncpus - 1) {
505 		db_printf("Invalid cpu number\n");
506 		return;
507 	}
508 	/*
509 	 * Lopp throug all the buffers and print the content of them, sorted
510 	 * by the timestamp.
511 	 */
512 	while (1) {
513 		int counter;
514 		u_int64_t highest_ts;
515 		int highest_cpu;
516 		struct ktr_entry *kp;
517 
518 		if (a_flag == 1 && cncheckc() != -1)
519 			return;
520 		highest_ts = 0;
521 		highest_cpu = -1;
522 		/*
523 		 * Find the lowest timestamp
524 		 */
525 		for (i = 0, counter = 0; i < ncpus; i++) {
526 			kcpu = &ktr_cpu[i].core;
527 			if (kcpu->ktr_buf == NULL)
528 				continue;
529 			if (printcpu != -1 && printcpu != i)
530 				continue;
531 			if (tstate[i].cur == -1) {
532 				counter++;
533 				if (counter == ncpus) {
534 					db_printf("--- End of trace buffer ---\n");
535 					return;
536 				}
537 				continue;
538 			}
539 			if (kcpu->ktr_buf[tstate[i].cur].ktr_timestamp > highest_ts) {
540 				highest_ts = kcpu->ktr_buf[tstate[i].cur].ktr_timestamp;
541 				highest_cpu = i;
542 			}
543 		}
544 		if (highest_cpu < 0) {
545 			db_printf("no KTR data available\n");
546 			break;
547 		}
548 		i = highest_cpu;
549 		kcpu = &ktr_cpu[i].core;
550 		kp = &kcpu->ktr_buf[tstate[i].cur];
551 		if (tstate[i].first == -1)
552 			tstate[i].first = tstate[i].cur;
553 		if (--tstate[i].cur < 0)
554 			tstate[i].cur = KTR_ENTRIES - 1;
555 		if (tstate[i].first == tstate[i].cur) {
556 			db_mach_vtrace(i, kp, tstate[i].cur + 1);
557 			tstate[i].cur = -1;
558 			continue;
559 		}
560 		if (kcpu->ktr_buf[tstate[i].cur].ktr_info == NULL)
561 			tstate[i].cur = -1;
562 		if (db_more(&nl) == -1)
563 			break;
564 		if (db_mach_vtrace(i, kp, tstate[i].cur + 1) == 0)
565 			tstate[i].cur = -1;
566 	}
567 }
568 
569 static int
570 db_mach_vtrace(int cpu, struct ktr_entry *kp, int idx)
571 {
572 	if (kp->ktr_info == NULL)
573 		return(0);
574 	db_printf("cpu%d ", cpu);
575 	db_printf("%d: ", idx);
576 	if (db_ktr_verbose) {
577 		db_printf("%10.10lld %s.%d\t", (long long)kp->ktr_timestamp,
578 		    kp->ktr_file, kp->ktr_line);
579 	}
580 	db_printf("%s\t", kp->ktr_info->kf_name);
581 	db_printf("from(%p,%p) ", kp->ktr_caller1, kp->ktr_caller2);
582 #ifdef __i386__
583 	if (kp->ktr_info->kf_format)
584 		db_vprintf(kp->ktr_info->kf_format, (__va_list)kp->ktr_data);
585 #endif
586 	db_printf("\n");
587 
588 	return(1);
589 }
590 
591 #endif	/* DDB */
592