summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Baulig <martin@src.gnome.org>1998-07-21 17:16:23 +0000
committerMartin Baulig <martin@src.gnome.org>1998-07-21 17:16:23 +0000
commitfc2d1f07c3f831266c0536aa5348d0f39238adad (patch)
treefdf5dea390bf4a0b7c9e9dd158ffa34d08d82294
parent694ad7adb743e7ce071ebcf81ab1eea260204689 (diff)
downloadlibgtop-fc2d1f07c3f831266c0536aa5348d0f39238adad.tar.gz
Initial revision
-rw-r--r--kernel/table21/Makefile16
-rw-r--r--kernel/table21/README21
-rw-r--r--kernel/table21/main.c61
-rw-r--r--kernel/table21/module.c524
-rw-r--r--kernel/table21/table.h166
-rw-r--r--kernel/table21/version.h1
6 files changed, 789 insertions, 0 deletions
diff --git a/kernel/table21/Makefile b/kernel/table21/Makefile
new file mode 100644
index 00000000..7d30495b
--- /dev/null
+++ b/kernel/table21/Makefile
@@ -0,0 +1,16 @@
+#
+# Makefile for the linux system information tables.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := table.o
+OX_OBJS := main.o
+
+M_TARGET := module.o
+MX_OBJS := module.o
+
+include $(TOPDIR)/Rules.make
diff --git a/kernel/table21/README b/kernel/table21/README
new file mode 100644
index 00000000..88d26bec
--- /dev/null
+++ b/kernel/table21/README
@@ -0,0 +1,21 @@
+This is a new system call `table ()' for the Linux table. It is faster
+than reading from /proc and can be used to fetch all information required
+for libgtop until whe have some other function (extended sysctl, ...) in
+standard kernels.
+
+I didn't want to change sysctl or some other function myself cause this may
+cause other applications relying upon those function to fail. This is
+something for the ``real'' kernel gurus ...
+
+To use this new system call for libgtop, do the following:
+
+* Copy this directory to /usr/src/linux/table
+* Make /usr/src/linux/include/linux/table.h symlink to /usr/src/linux/table/table.h
+* Apply the patch `kernel.patch' to the kernel, compile, install and reboot
+* Recompile libgtop (remove `config.cache' and run the `autogen.sh' again).
+
+If you want to change and/or add something - feel free to do so !
+
+Have fun,
+
+Martin
diff --git a/kernel/table21/main.c b/kernel/table21/main.c
new file mode 100644
index 00000000..e6d1882b
--- /dev/null
+++ b/kernel/table21/main.c
@@ -0,0 +1,61 @@
+/*
+ * linux/table/table_impl.c
+ * Copyright (C) 1998 Martin Baulig
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/tty.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/string.h>
+#include <linux/mman.h>
+#include <linux/proc_fs.h>
+#include <linux/ioport.h>
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/signal.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+
+#include <linux/module.h>
+#include <linux/table.h>
+
+#include "version.h"
+
+extern void scheduling_functions_start_here(void);
+extern void scheduling_functions_end_here(void);
+
+int (*table_function_ptr) (int, union table *, const void *) = 0;
+
+EXPORT_SYMBOL(table_function_ptr);
+
+EXPORT_SYMBOL(nr_running);
+EXPORT_SYMBOL(pidhash);
+EXPORT_SYMBOL(task);
+EXPORT_SYMBOL(si_swapinfo);
+EXPORT_SYMBOL(scheduling_functions_start_here);
+EXPORT_SYMBOL(scheduling_functions_end_here);
+EXPORT_SYMBOL(avenrun);
+EXPORT_SYMBOL(nr_tasks);
+EXPORT_SYMBOL(last_pid);
+EXPORT_SYMBOL(page_cache_size);
+EXPORT_SYMBOL(init_mm);
+
+asmlinkage int
+sys_table (int type, union table *buf, const void *param)
+{
+ if (table_function_ptr == 0)
+ return -ENOSYS;
+
+ return (*table_function_ptr) (type, buf, param);
+}
diff --git a/kernel/table21/module.c b/kernel/table21/module.c
new file mode 100644
index 00000000..b23fb053
--- /dev/null
+++ b/kernel/table21/module.c
@@ -0,0 +1,524 @@
+/*
+ * linux/table/table_impl.c
+ * Copyright (C) 1998 Martin Baulig
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/tty.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/string.h>
+#include <linux/mman.h>
+#include <linux/proc_fs.h>
+#include <linux/ioport.h>
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/signal.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+
+#include <linux/module.h>
+#include <linux/table.h>
+
+#include "version.h"
+
+extern int (*table_function_ptr) (int, union table *, const void *);
+
+int table_fkt (int, union table *, const void *);
+
+EXPORT_NO_SYMBOLS;
+
+int
+init_module(void)
+{
+ printk ("init_module () = %p\n", table_fkt);
+ table_function_ptr = table_fkt;
+ return 0;
+}
+
+void
+cleanup_module(void)
+{
+ table_function_ptr = 0;
+}
+
+#define LOAD_INT(x) ((x) >> FSHIFT)
+#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
+
+#ifdef CONFIG_DEBUG_MALLOC
+int get_malloc(char * buffer);
+#endif
+
+static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign,
+ sigset_t *catch)
+{
+ struct k_sigaction *k;
+ int i;
+
+ sigemptyset(ign);
+ sigemptyset(catch);
+
+ if (p->sig) {
+ k = p->sig->action;
+ for (i = 1; i <= _NSIG; ++i, ++k) {
+ if (k->sa.sa_handler == SIG_IGN)
+ sigaddset(ign, i);
+ else if (k->sa.sa_handler != SIG_DFL)
+ sigaddset(catch, i);
+ }
+ }
+}
+
+/*
+ * These bracket the sleeping functions..
+ */
+extern void scheduling_functions_start_here(void);
+extern void scheduling_functions_end_here(void);
+#define first_sched ((unsigned long) scheduling_functions_start_here)
+#define last_sched ((unsigned long) scheduling_functions_end_here)
+
+static unsigned long get_wchan(struct task_struct *p)
+{
+ if (!p || p == current || p->state == TASK_RUNNING)
+ return 0;
+#if defined(__i386__)
+ {
+ unsigned long ebp, eip;
+ unsigned long stack_page;
+ int count = 0;
+
+ stack_page = 4096 + (unsigned long)p;
+ if (!stack_page)
+ return 0;
+ ebp = p->tss.ebp;
+ do {
+ if (ebp < stack_page || ebp >= 4092+stack_page)
+ return 0;
+ eip = *(unsigned long *) (ebp+4);
+ if (eip < first_sched || eip >= last_sched)
+ return eip;
+ ebp = *(unsigned long *) ebp;
+ } while (count++ < 16);
+ }
+#elif defined(__alpha__)
+ /*
+ * This one depends on the frame size of schedule(). Do a
+ * "disass schedule" in gdb to find the frame size. Also, the
+ * code assumes that sleep_on() follows immediately after
+ * interruptible_sleep_on() and that add_timer() follows
+ * immediately after interruptible_sleep(). Ugly, isn't it?
+ * Maybe adding a wchan field to task_struct would be better,
+ * after all...
+ */
+ {
+ unsigned long schedule_frame;
+ unsigned long pc;
+
+ pc = thread_saved_pc(&p->tss);
+ if (pc >= first_sched && pc < last_sched) {
+ schedule_frame = ((unsigned long *)p->tss.ksp)[6];
+ return ((unsigned long *)schedule_frame)[12];
+ }
+ return pc;
+ }
+#elif defined(__mc68000__)
+ {
+ unsigned long fp, pc;
+ unsigned long stack_page;
+ int count = 0;
+ extern int sys_pause (void);
+
+ stack_page = p->kernel_stack_page;
+ if (!stack_page)
+ return 0;
+ fp = ((struct switch_stack *)p->tss.ksp)->a6;
+ do {
+ if (fp < stack_page || fp >= 4088+stack_page)
+ return 0;
+ pc = ((unsigned long *)fp)[1];
+ /* FIXME: This depends on the order of these functions. */
+ if (pc < first_sched || pc >= last_sched)
+ return pc;
+ fp = *(unsigned long *) fp;
+ } while (count++ < 16);
+ }
+#elif defined(__powerpc__)
+ return (p->tss.wchan);
+#elif defined (CONFIG_ARM)
+ {
+ unsigned long fp, lr;
+ unsigned long stack_page;
+ int count = 0;
+
+ stack_page = 4096 + (unsigned long)p;
+ fp = get_css_fp (&p->tss);
+ do {
+ if (fp < stack_page || fp > 4092+stack_page)
+ return 0;
+ lr = pc_pointer (((unsigned long *)fp)[-1]);
+ if (lr < first_sched || lr > last_sched)
+ return lr;
+ fp = *(unsigned long *) (fp - 12);
+ } while (count ++ < 16);
+ }
+#endif
+ return 0;
+}
+
+#if defined(__i386__)
+# define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1019])
+# define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022])
+#elif defined(__alpha__)
+ /*
+ * See arch/alpha/kernel/ptrace.c for details.
+ */
+# define PT_REG(reg) (PAGE_SIZE - sizeof(struct pt_regs) \
+ + (long)&((struct pt_regs *)0)->reg)
+# define KSTK_EIP(tsk) \
+ (*(unsigned long *)(PT_REG(pc) + PAGE_SIZE + (unsigned long)(tsk)))
+# define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->tss.usp)
+#elif defined(CONFIG_ARM)
+# define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022])
+# define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1020])
+#elif defined(__mc68000__)
+#define KSTK_EIP(tsk) \
+ ({ \
+ unsigned long eip = 0; \
+ if ((tsk)->tss.esp0 > PAGE_SIZE && \
+ MAP_NR((tsk)->tss.esp0) < max_mapnr) \
+ eip = ((struct pt_regs *) (tsk)->tss.esp0)->pc; \
+ eip; })
+#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->tss.usp)
+#elif defined(__powerpc__)
+#define KSTK_EIP(tsk) ((tsk)->tss.regs->nip)
+#define KSTK_ESP(tsk) ((tsk)->tss.regs->gpr[1])
+#elif defined (__sparc_v9__)
+# define KSTK_EIP(tsk) ((tsk)->tss.kregs->tpc)
+# define KSTK_ESP(tsk) ((tsk)->tss.kregs->u_regs[UREG_FP])
+#elif defined(__sparc__)
+# define KSTK_EIP(tsk) ((tsk)->tss.kregs->pc)
+# define KSTK_ESP(tsk) ((tsk)->tss.kregs->u_regs[UREG_FP])
+#endif
+
+/* Gcc optimizes away "strlen(x)" for constant x */
+#define ADDBUF(buffer, string) \
+do { memcpy(buffer, string, strlen(string)); \
+ buffer += strlen(string); } while (0)
+
+static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size,
+ int * pages, int * shared, int * dirty, int * total)
+{
+ pte_t * pte;
+ unsigned long end;
+
+ if (pmd_none(*pmd))
+ return;
+ if (pmd_bad(*pmd)) {
+ printk("statm_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd));
+ pmd_clear(pmd);
+ return;
+ }
+ pte = pte_offset(pmd, address);
+ address &= ~PMD_MASK;
+ end = address + size;
+ if (end > PMD_SIZE)
+ end = PMD_SIZE;
+ do {
+ pte_t page = *pte;
+
+ address += PAGE_SIZE;
+ pte++;
+ if (pte_none(page))
+ continue;
+ ++*total;
+ if (!pte_present(page))
+ continue;
+ ++*pages;
+ if (pte_dirty(page))
+ ++*dirty;
+ if (MAP_NR(pte_page(page)) >= max_mapnr)
+ continue;
+ if (atomic_read(&mem_map[MAP_NR(pte_page(page))].count) > 1)
+ ++*shared;
+ } while (address < end);
+}
+
+static inline void statm_pmd_range(pgd_t * pgd, unsigned long address, unsigned long size,
+ int * pages, int * shared, int * dirty, int * total)
+{
+ pmd_t * pmd;
+ unsigned long end;
+
+ if (pgd_none(*pgd))
+ return;
+ if (pgd_bad(*pgd)) {
+ printk("statm_pmd_range: bad pgd (%08lx)\n", pgd_val(*pgd));
+ pgd_clear(pgd);
+ return;
+ }
+ pmd = pmd_offset(pgd, address);
+ address &= ~PGDIR_MASK;
+ end = address + size;
+ if (end > PGDIR_SIZE)
+ end = PGDIR_SIZE;
+ do {
+ statm_pte_range(pmd, address, end - address, pages, shared, dirty, total);
+ address = (address + PMD_SIZE) & PMD_MASK;
+ pmd++;
+ } while (address < end);
+}
+
+static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long end,
+ int * pages, int * shared, int * dirty, int * total)
+{
+ while (address < end) {
+ statm_pmd_range(pgd, address, end - address, pages, shared, dirty, total);
+ address = (address + PGDIR_SIZE) & PGDIR_MASK;
+ pgd++;
+ }
+}
+
+int
+table_fkt (int type, union table *buf, const void *param)
+{
+ union table tbl;
+ struct sysinfo i;
+ struct task_struct *tsk = NULL;
+ int index, err;
+ pid_t pid;
+
+ if (type == TABLE_VERSION)
+ return _TABLE_VERSION;
+
+ if (!buf)
+ return -EFAULT;
+
+ memset (&tbl, 0, sizeof (union table));
+
+ /* For TABLE_PROC_*, read pid and get task_struct */
+
+ switch (type) {
+ case TABLE_PROC_UID:
+ case TABLE_PROC_MEM:
+ case TABLE_PROC_SEGMENT:
+ case TABLE_PROC_TIME:
+ case TABLE_PROC_STATE:
+ case TABLE_PROC_SIGNAL:
+ case TABLE_PROC_KERNEL:
+ err = verify_area (VERIFY_READ, param, sizeof (pid_t));
+ if (err)
+ return err;
+ copy_from_user (&pid, param, sizeof (pid_t));
+
+ read_lock (&tasklist_lock);
+ tsk = find_task_by_pid (pid);
+ /* FIXME!! This should be done after the last use */
+ read_unlock(&tasklist_lock);
+
+ if (tsk == NULL)
+ return -ESRCH;
+ break;
+ }
+
+ /* Main function dispatcher */
+
+ switch (type) {
+ case TABLE_PROCLIST:
+ tsk = task [0];
+ for (index = 0; index < nr_tasks; index++) {
+ tbl.proclist.pids [index] = tsk->pid;
+ tsk = tsk->next_task;
+ }
+ tbl.proclist.nr_running = nr_running;
+ tbl.proclist.nr_tasks = nr_tasks;
+ tbl.proclist.last_pid = last_pid;
+ break;
+ case TABLE_CPU:
+ tbl.cpu.total = jiffies;
+ tbl.cpu.user = kstat.cpu_user;
+ tbl.cpu.nice = kstat.cpu_nice;
+ tbl.cpu.sys = kstat.cpu_system;
+ tbl.cpu.idle = tbl.cpu.total -
+ (tbl.cpu.user + tbl.cpu.nice + tbl.cpu.sys);
+ tbl.cpu.frequency = HZ;
+ break;
+ case TABLE_MEM:
+ si_meminfo (&i);
+ tbl.mem.total = i.totalram;
+ tbl.mem.used = i.totalram - i.freeram;
+ tbl.mem.free = i.freeram;
+ tbl.mem.shared = i.sharedram;
+ tbl.mem.buffer = i.bufferram;
+ tbl.mem.cached = page_cache_size << PAGE_SHIFT;
+ break;
+ case TABLE_SWAP:
+ si_swapinfo (&i);
+ tbl.swap.total = i.totalswap;
+ tbl.swap.used = i.totalswap - i.freeswap;
+ tbl.swap.free = i.freeswap;
+ break;
+ case TABLE_LOADAVG:
+ tbl.loadavg.loadavg [0] = (double) avenrun [0] / (1 << FSHIFT);
+ tbl.loadavg.loadavg [1] = (double) avenrun [1] / (1 << FSHIFT);
+ tbl.loadavg.loadavg [2] = (double) avenrun [2] / (1 << FSHIFT);
+ tbl.loadavg.nr_running = nr_running;
+ tbl.loadavg.nr_tasks = nr_tasks;
+ tbl.loadavg.last_pid = last_pid;
+ break;
+ case TABLE_UPTIME:
+ tbl.uptime.uptime = jiffies;
+ tbl.uptime.idle = task[0]->times.tms_utime +
+ task[0]->times.tms_stime;
+ break;
+ case TABLE_PROC_STATE:
+ tbl.proc_state.state = tsk->state;
+ tbl.proc_state.flags = tsk->flags;
+ memcpy (tbl.proc_state.comm, tsk->comm,
+ sizeof (tbl.proc_state.comm));
+ break;
+ case TABLE_PROC_UID:
+ tbl.proc_uid.uid = tsk->uid;
+ tbl.proc_uid.euid = tsk->euid;
+ tbl.proc_uid.suid = tsk->suid;
+ tbl.proc_uid.fsuid = tsk->fsuid;
+
+ tbl.proc_uid.gid = tsk->gid;
+ tbl.proc_uid.egid = tsk->egid;
+ tbl.proc_uid.sgid = tsk->sgid;
+ tbl.proc_uid.fsgid = tsk->fsgid;
+
+ tbl.proc_uid.pid = tsk->pid;
+ tbl.proc_uid.pgrp = tsk->pgrp;
+ tbl.proc_uid.ppid = tsk->p_pptr->pid;
+
+ tbl.proc_uid.session = tsk->session;
+ tbl.proc_uid.tty = tsk->tty ?
+ kdev_t_to_nr (tsk->tty->device) : 0;
+ tbl.proc_uid.tpgid = tsk->tty ? tsk->tty->pgrp : -1;
+
+ tbl.proc_uid.priority = tsk->priority;
+ tbl.proc_uid.counter = tsk->counter;
+ tbl.proc_uid.def_priority = DEF_PRIORITY;
+ break;
+ case TABLE_PROC_SIGNAL:
+ tbl.proc_signal.signal = tsk->signal;
+ tbl.proc_signal.blocked = tsk->blocked;
+
+ collect_sigign_sigcatch (tsk, &tbl.proc_signal.ignored,
+ &tbl.proc_signal.caught);
+ break;
+ case TABLE_PROC_MEM:
+ if (tsk->mm && tsk->mm != &init_mm) {
+ tbl.proc_mem.context = tsk->mm->context;
+ tbl.proc_mem.start_code = tsk->mm->start_code;
+ tbl.proc_mem.end_code = tsk->mm->end_code;
+ tbl.proc_mem.start_data = tsk->mm-> start_data;
+ tbl.proc_mem.end_data = tsk->mm->end_data;
+ tbl.proc_mem.start_brk = tsk->mm->start_brk;
+ tbl.proc_mem.brk = tsk->mm->brk;
+ tbl.proc_mem.start_stack = tsk->mm->start_stack;
+ tbl.proc_mem.start_mmap = tsk->mm->mmap ?
+ tsk->mm->mmap->vm_start : 0;
+ tbl.proc_mem.arg_start = tsk->mm->arg_start;
+ tbl.proc_mem.arg_end = tsk->mm->arg_end;
+ tbl.proc_mem.env_start = tsk->mm->env_start;
+ tbl.proc_mem.env_end = tsk->mm->env_end;
+ tbl.proc_mem.rss = tsk->mm->rss;
+ tbl.proc_mem.total_vm = tsk->mm->total_vm;
+ tbl.proc_mem.locked_vm = tsk->mm->locked_vm;
+ }
+ tbl.proc_mem.rlim = tsk->rlim ? tsk->rlim[RLIMIT_RSS].rlim_cur : 0;
+ break;
+ case TABLE_PROC_SEGMENT:
+ if (tsk->mm && tsk->mm != &init_mm) {
+ unsigned long vsize = 0;
+ int size = 0, resident = 0, share = 0;
+ int trs = 0, lrs = 0, drs = 0, dt = 0;
+ struct vm_area_struct * vma = tsk->mm->mmap;
+
+ while (vma) {
+ pgd_t *pgd = pgd_offset(tsk->mm, vma->vm_start);
+ int pages = 0, shared = 0, dirty = 0, total = 0;
+
+ vsize += vma->vm_end - vma->vm_start;
+
+ statm_pgd_range (pgd, vma->vm_start, vma->vm_end,
+ &pages, &shared, &dirty, &total);
+ resident += pages;
+ share += shared;
+ dt += dirty;
+ size += total;
+ if (vma->vm_flags & VM_EXECUTABLE)
+ trs += pages; /* text */
+ else if (vma->vm_flags & VM_GROWSDOWN)
+ drs += pages; /* stack */
+ else if (vma->vm_end > 0x60000000)
+ lrs += pages; /* library */
+ else
+ drs += pages;
+ vma = vma->vm_next;
+ }
+
+ tbl.proc_segment.vsize = vsize;
+ tbl.proc_segment.size = size;
+ tbl.proc_segment.resident = resident;
+ tbl.proc_segment.shared = share;
+ tbl.proc_segment.trs = trs;
+ tbl.proc_segment.lrs = lrs;
+ tbl.proc_segment.dt = dt;
+ }
+ break;
+ case TABLE_PROC_TIME:
+ tbl.proc_time.utime = tsk->times.tms_utime;
+ tbl.proc_time.stime = tsk->times.tms_stime;
+ tbl.proc_time.cutime = tsk->times.tms_cutime;
+ tbl.proc_time.cstime = tsk->times.tms_cstime;
+
+ tbl.proc_time.start_time = tsk->start_time;
+ tbl.proc_time.timeout = tsk->timeout;
+ tbl.proc_time.policy = tsk->policy;
+ tbl.proc_time.rt_priority = tsk->rt_priority;
+
+ tbl.proc_time.it_real_value = tsk->it_real_value;
+ tbl.proc_time.it_prof_value = tsk->it_prof_value;
+ tbl.proc_time.it_virt_value = tsk->it_virt_value;
+ tbl.proc_time.it_real_incr = tsk->it_real_incr;
+ tbl.proc_time.it_prof_incr = tsk->it_prof_incr;
+ tbl.proc_time.it_virt_incr = tsk->it_virt_incr;
+ break;
+ case TABLE_PROC_KERNEL:
+ tbl.proc_kernel.min_flt = tsk->min_flt;
+ tbl.proc_kernel.cmin_flt = tsk->cmin_flt;
+ tbl.proc_kernel.maj_flt = tsk->maj_flt;
+ tbl.proc_kernel.cmaj_flt = tsk->cmaj_flt;
+
+ tbl.proc_kernel.kesp = KSTK_EIP(tsk);
+ tbl.proc_kernel.keip = KSTK_ESP(tsk);
+
+ tbl.proc_kernel.nswap = tsk->nswap;
+ tbl.proc_kernel.cnswap = tsk->cnswap;
+
+ tbl.proc_kernel.wchan = get_wchan (tsk);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = verify_area (VERIFY_WRITE, buf, sizeof (struct table));
+ if (err)
+ return err;
+
+ copy_to_user (buf, &tbl, sizeof (union table));
+
+ return 0;
+}
diff --git a/kernel/table21/table.h b/kernel/table21/table.h
new file mode 100644
index 00000000..51aabf62
--- /dev/null
+++ b/kernel/table21/table.h
@@ -0,0 +1,166 @@
+#ifndef _LINUX_TABLE_H
+#define _LINUX_TABLE_H
+
+#ifdef _KERNEL
+#include <linux/types.h>
+#else
+#define NR_TASKS 512
+#endif
+
+#define TABLE_VERSION 0
+#define TABLE_CPU 1
+#define TABLE_MEM 2
+#define TABLE_SWAP 3
+#define TABLE_LOADAVG 4
+#define TABLE_UPTIME 5
+#define TABLE_PROCLIST 6
+#define TABLE_PROC_UID 7
+#define TABLE_PROC_MEM 8
+#define TABLE_PROC_SEGMENT 9
+#define TABLE_PROC_TIME 10
+#define TABLE_PROC_STATE 11
+#define TABLE_PROC_SIGNAL 12
+#define TABLE_PROC_KERNEL 13
+
+/* CPU Usage (in jiffies = 1/100th seconds) */
+
+struct table_cpu
+{
+ unsigned long total; /* Total CPU Time */
+ unsigned long user; /* CPU Time in User Mode */
+ unsigned long nice; /* CPU Time in User Mode (nice) */
+ unsigned long sys; /* CPU Time in System Mode */
+ unsigned long idle; /* CPU Time in the Idle Task */
+ unsigned long frequency; /* Tick frequency */
+};
+
+/* Memory Usage (in bytes) */
+
+struct table_mem
+{
+ unsigned long total; /* Total physical memory */
+ unsigned long used; /* Used memory size */
+ unsigned long free; /* Free memory size */
+ unsigned long shared; /* Shared memory size */
+ unsigned long buffer; /* Size of buffers */
+ unsigned long cached; /* Size of cached memory */
+};
+
+/* Swap Space (in bytes) */
+
+struct table_swap
+{
+ unsigned long total; /* Total swap space */
+ unsigned long used; /* Used swap space */
+ unsigned long free; /* Free swap space */
+};
+
+/* Load average */
+
+struct table_loadavg
+{
+ double loadavg [3];
+ unsigned nr_running;
+ unsigned nr_tasks;
+ unsigned last_pid;
+};
+
+/* Uptime */
+
+struct table_uptime
+{
+ unsigned long uptime;
+ unsigned long idle;
+};
+
+/* Process list. */
+
+struct table_proclist
+{
+ int nr_running, nr_tasks, last_pid;
+ unsigned pids [NR_TASKS];
+};
+
+/* Information about processes. */
+
+struct table_proc_state
+{
+ long state;
+ unsigned long flags;
+ char comm[16];
+};
+
+struct table_proc_uid
+{
+ int uid, euid, suid, fsuid;
+ int gid, egid, sgid, fsgid;
+ int pid, pgrp, ppid;
+ int session;
+ unsigned int tty;
+ int tpgid;
+ long priority;
+ long counter;
+ long def_priority;
+};
+
+struct table_proc_mem
+{
+ unsigned long context;
+ unsigned long start_code, end_code, start_data, end_data;
+ unsigned long start_brk, brk, start_stack, start_mmap;
+ unsigned long arg_start, arg_end, env_start, env_end;
+ unsigned long rss, rlim, total_vm, locked_vm;
+};
+
+struct table_proc_segment
+{
+ unsigned long vsize;
+ int size, resident, shared;
+ int trs, lrs, drs, dt;
+};
+
+struct table_proc_time
+{
+ long utime, stime, cutime, cstime, start_time;
+ unsigned long timeout, policy, rt_priority;
+ unsigned long it_real_value, it_prof_value, it_virt_value;
+ unsigned long it_real_incr, it_prof_incr, it_virt_incr;
+};
+
+struct table_proc_signal
+{
+ sigset_t signal;
+ sigset_t blocked; /* bitmap of masked signals */
+ sigset_t ignored; /* mask of ignored signals */
+ sigset_t caught; /* mask of caught signals */
+};
+
+struct table_proc_kernel
+{
+ unsigned long keip, kesp, wchan;
+ unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt;
+ unsigned long nswap, cnswap;
+};
+
+/* Union */
+
+union table
+{
+ struct table_cpu cpu;
+ struct table_mem mem;
+ struct table_swap swap;
+ struct table_loadavg loadavg;
+ struct table_uptime uptime;
+ struct table_proclist proclist;
+ struct table_proc_uid proc_uid;
+ struct table_proc_mem proc_mem;
+ struct table_proc_segment proc_segment;
+ struct table_proc_time proc_time;
+ struct table_proc_state proc_state;
+ struct table_proc_signal proc_signal;
+ struct table_proc_kernel proc_kernel;
+};
+
+#endif /* _LINUX_IPC_H */
+
+
diff --git a/kernel/table21/version.h b/kernel/table21/version.h
new file mode 100644
index 00000000..d47411ee
--- /dev/null
+++ b/kernel/table21/version.h
@@ -0,0 +1 @@
+#define _TABLE_VERSION 1