Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys Create kernel thread and let it to issue the write reque...
details: https://anonhg.NetBSD.org/src/rev/f745941ec941
branches: trunk
changeset: 570083:f745941ec941
user: enami <enami%NetBSD.org@localhost>
date: Wed Sep 22 22:15:03 2004 +0000
description:
Create kernel thread and let it to issue the write request. We can't
do this from trace target process since we can't sleep at certain
trace point (otherwise system may hang). Address PR#23155.
diffstat:
sys/kern/kern_ktrace.c | 947 +++++++++++++++++++++++++++++++++++-------------
sys/sys/ktrace.h | 24 +-
2 files changed, 691 insertions(+), 280 deletions(-)
diffs (truncated from 1279 to 300 lines):
diff -r 04d4e9b65cab -r f745941ec941 sys/kern/kern_ktrace.c
--- a/sys/kern/kern_ktrace.c Wed Sep 22 21:24:07 2004 +0000
+++ b/sys/kern/kern_ktrace.c Wed Sep 22 22:15:03 2004 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_ktrace.c,v 1.92 2004/09/04 07:09:35 skrll Exp $ */
+/* $NetBSD: kern_ktrace.c,v 1.93 2004/09/22 22:15:03 enami Exp $ */
/*
* Copyright (c) 1989, 1993
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_ktrace.c,v 1.92 2004/09/04 07:09:35 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_ktrace.c,v 1.93 2004/09/22 22:15:03 enami Exp $");
#include "opt_ktrace.h"
#include "opt_compat_mach.h"
@@ -43,11 +43,14 @@
#include <sys/file.h>
#include <sys/namei.h>
#include <sys/vnode.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
#include <sys/ktrace.h>
#include <sys/malloc.h>
#include <sys/syslog.h>
#include <sys/filedesc.h>
#include <sys/ioctl.h>
+#include <sys/callout.h>
#include <sys/mount.h>
#include <sys/sa.h>
@@ -55,14 +58,285 @@
#ifdef KTRACE
-void ktrinitheader(struct ktr_header *, struct proc *, int);
-int ktrwrite(struct proc *, struct ktr_header *);
-int ktrace_common(struct proc *, int, int, int, struct file *);
-int ktrops(struct proc *, struct proc *, int, int, struct file *);
-int ktrsetchildren(struct proc *, struct proc *, int, int,
- struct file *);
-int ktrcanset(struct proc *, struct proc *);
-int ktrsamefile(struct file *, struct file *);
+/*
+ * XXX:
+ * - need better error reporting?
+ * - p->p_tracep access lock. lock p_lock, lock ktd if !NULL, inc ref.
+ * - userland utility to sort ktrace.out by timestamp.
+ * - keep minimum information in ktrace_entry when rest of alloc failed.
+ * - enlarge ktrace_entry so that small entry won't require additional
+ * alloc?
+ * - per trace control of configurable parameters.
+ */
+
+struct ktrace_entry {
+ TAILQ_ENTRY(ktrace_entry) kte_list;
+ struct ktr_header kte_kth;
+ void *kte_buf; /* ktr_buf */
+};
+
+struct ktr_desc {
+ TAILQ_ENTRY(ktr_desc) ktd_list;
+ int ktd_flags;
+#define KTDF_WAIT 0x0001
+#define KTDF_DONE 0x0002
+#define KTDF_BLOCKING 0x0004
+#define KTDF_INTERACTIVE 0x0008
+ int ktd_error;
+#define KTDE_ENOMEM 0x0001
+#define KTDE_ENOSPC 0x0002
+ int ktd_errcnt;
+ int ktd_ref; /* # of reference */
+ int ktd_qcount; /* # of entry in the queue */
+
+ /*
+ * Params to control behaviour.
+ */
+ int ktd_delayqcnt; /* # of entry allowed to delay */
+ int ktd_wakedelay; /* delay of wakeup in *tick* */
+ int ktd_intrwakdl; /* ditto, but when interactive */
+
+ struct file *ktd_fp; /* trace output file */
+ struct proc *ktd_proc; /* our kernel thread */
+ TAILQ_HEAD(, ktrace_entry) ktd_queue;
+ struct callout ktd_wakch; /* delayed wakeup */
+ struct simplelock ktd_slock;
+};
+
+static void ktrinitheader(struct ktr_header *, struct proc *, int);
+static void ktrwrite(struct ktr_desc *, struct ktrace_entry *);
+static int ktrace_common(struct proc *, int, int, int, struct file *);
+static int ktrops(struct proc *, struct proc *, int, int,
+ struct ktr_desc *);
+static int ktrsetchildren(struct proc *, struct proc *, int, int,
+ struct ktr_desc *);
+static int ktrcanset(struct proc *, struct proc *);
+static int ktrsamefile(struct file *, struct file *);
+
+static struct ktr_desc *
+ ktd_lookup(struct file *);
+static void ktdrel(struct ktr_desc *);
+static void ktdref(struct ktr_desc *);
+static void ktraddentry(struct proc *, struct ktrace_entry *, int);
+/* Flags for ktraddentry (3rd arg) */
+#define KTA_NOWAIT 0x0000
+#define KTA_WAITOK 0x0001
+#define KTA_LARGE 0x0002
+static void ktefree(struct ktrace_entry *);
+static void ktd_logerrl(struct ktr_desc *, int);
+static void ktd_logerr(struct proc *, int);
+static void ktrace_thread(void *);
+
+/*
+ * Default vaules.
+ */
+#define KTD_MAXENTRY 1000 /* XXX: tune */
+#define KTD_TIMEOUT 5 /* XXX: tune */
+#define KTD_DELAYQCNT 100 /* XXX: tune */
+#define KTD_WAKEDELAY 5000 /* XXX: tune */
+#define KTD_INTRWAKDL 100 /* XXX: tune */
+
+/*
+ * Patchable variables.
+ */
+int ktd_maxentry = KTD_MAXENTRY; /* max # of entry in the queue */
+int ktd_timeout = KTD_TIMEOUT; /* timeout in seconds */
+int ktd_delayqcnt = KTD_DELAYQCNT; /* # of entry allowed to delay */
+int ktd_wakedelay = KTD_WAKEDELAY; /* delay of wakeup in *ms* */
+int ktd_intrwakdl = KTD_INTRWAKDL; /* ditto, but when interactive */
+
+static struct simplelock ktdq_slock = SIMPLELOCK_INITIALIZER;
+static TAILQ_HEAD(, ktr_desc) ktdq = TAILQ_HEAD_INITIALIZER(ktdq);
+
+MALLOC_DEFINE(M_KTRACE, "ktrace", "ktrace data buffer");
+POOL_INIT(kte_pool, sizeof(struct ktrace_entry), 0, 0, 0,
+ "ktepl", &pool_allocator_nointr);
+
+static __inline void
+ktd_wakeup(struct ktr_desc *ktd)
+{
+
+ callout_stop(&ktd->ktd_wakch);
+ wakeup(ktd);
+}
+
+static void
+ktd_logerrl(struct ktr_desc *ktd, int error)
+{
+
+ ktd->ktd_error |= error;
+ ktd->ktd_errcnt++;
+}
+
+static void
+ktd_logerr(struct proc *p, int error)
+{
+ struct ktr_desc *ktd = p->p_tracep;
+
+ if (ktd == NULL)
+ return;
+
+ simple_lock(&ktd->ktd_slock);
+ ktd_logerrl(ktd, error);
+ simple_unlock(&ktd->ktd_slock);
+}
+
+/*
+ * Release a reference. Called with ktd_slock held.
+ */
+void
+ktdrel(struct ktr_desc *ktd)
+{
+
+ KDASSERT(ktd->ktd_ref != 0);
+ KASSERT(ktd->ktd_ref > 0);
+ if (--ktd->ktd_ref <= 0) {
+ ktd->ktd_flags |= KTDF_DONE;
+ wakeup(ktd);
+ }
+ simple_unlock(&ktd->ktd_slock);
+}
+
+void
+ktdref(struct ktr_desc *ktd)
+{
+
+ simple_lock(&ktd->ktd_slock);
+ ktd->ktd_ref++;
+ simple_unlock(&ktd->ktd_slock);
+}
+
+struct ktr_desc *
+ktd_lookup(struct file *fp)
+{
+ struct ktr_desc *ktd;
+
+ simple_lock(&ktdq_slock);
+ for (ktd = TAILQ_FIRST(&ktdq); ktd != NULL;
+ ktd = TAILQ_NEXT(ktd, ktd_list)) {
+ simple_lock(&ktd->ktd_slock);
+ if (ktrsamefile(ktd->ktd_fp, fp)) {
+ ktd->ktd_ref++;
+ simple_unlock(&ktd->ktd_slock);
+ break;
+ }
+ simple_unlock(&ktd->ktd_slock);
+ }
+ simple_unlock(&ktdq_slock);
+ return (ktd);
+}
+
+void
+ktraddentry(struct proc *p, struct ktrace_entry *kte, int flags)
+{
+ struct ktr_desc *ktd;
+#ifdef DEBUG
+ struct timeval t;
+ int s;
+#endif
+
+ if (p->p_traceflag & KTRFAC_TRC_EMUL) {
+ /* Add emulation trace before first entry for this process */
+ p->p_traceflag &= ~KTRFAC_TRC_EMUL;
+ ktremul(p);
+ }
+
+ /*
+ * Tracing may be canceled while we were sleeping waiting for
+ * memory.
+ */
+ ktd = p->p_tracep;
+ if (ktd == NULL)
+ goto freekte;
+
+ /*
+ * Bump reference count so that the object will remain while
+ * we are here. Note that the trace is controlled by other
+ * process.
+ */
+ ktdref(ktd);
+
+ simple_lock(&ktd->ktd_slock);
+ if (ktd->ktd_flags & KTDF_DONE)
+ goto relktd;
+
+ if (ktd->ktd_qcount > ktd_maxentry) {
+ ktd_logerrl(ktd, KTDE_ENOSPC);
+ goto relktd;
+ }
+ TAILQ_INSERT_TAIL(&ktd->ktd_queue, kte, kte_list);
+ ktd->ktd_qcount++;
+ if (ktd->ktd_flags & KTDF_BLOCKING)
+ goto skip_sync;
+
+ if (flags & KTA_WAITOK &&
+ (/* flags & KTA_LARGE */0 || ktd->ktd_flags & KTDF_WAIT ||
+ ktd->ktd_qcount > ktd_maxentry >> 1))
+ /*
+ * Sync with writer thread since we're requesting rather
+ * big one or many requests are pending.
+ */
+ do {
+ ktd->ktd_flags |= KTDF_WAIT;
+ ktd_wakeup(ktd);
+#ifdef DEBUG
+ s = splclock();
+ t = mono_time;
+ splx(s);
+#endif
+ if (ltsleep(&ktd->ktd_flags, PWAIT, "ktrsync",
+ ktd_timeout * hz, &ktd->ktd_slock) != 0) {
+ ktd->ktd_flags |= KTDF_BLOCKING;
+ /*
+ * Maybe the writer thread is blocking
+ * completely for some reason, but
+ * don't stop target process forever.
+ */
+ log(LOG_NOTICE, "ktrace timeout\n");
+ break;
+ }
+#ifdef DEBUG
+ s = splclock();
+ timersub(&mono_time, &t, &t);
+ splx(s);
+ if (t.tv_sec > 0)
+ log(LOG_NOTICE,
+ "ktrace long wait: %ld.%06ld\n",
+ t.tv_sec, t.tv_usec);
+#endif
+ } while (p->p_tracep == ktd &&
+ (ktd->ktd_flags & (KTDF_WAIT | KTDF_DONE)) == KTDF_WAIT);
+ else {
+ /* Schedule delayed wakeup */
+ if (ktd->ktd_qcount > ktd->ktd_delayqcnt)
+ ktd_wakeup(ktd); /* Wakeup now */
+ else if (!callout_pending(&ktd->ktd_wakch))
+ callout_reset(&ktd->ktd_wakch,
+ ktd->ktd_flags & KTDF_INTERACTIVE ?
Home |
Main Index |
Thread Index |
Old Index