Module: xenomai-rpm
Branch: queue/vfile
Commit: 25fb7b8fbf5dcab4b5f2c5cc0fa58a679d662d51
URL:    
http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=25fb7b8fbf5dcab4b5f2c5cc0fa58a679d662d51

Author: Philippe Gerum <r...@xenomai.org>
Date:   Thu Apr 29 18:22:32 2010 +0200

native: convert to vfile

---

 ksrc/nucleus/heap.c        |    2 +-
 ksrc/skins/native/alarm.c  |  146 ++++++++++++++++++++++++-----------
 ksrc/skins/native/buffer.c |  181 +++++++++++++++++++++++++++++---------------
 ksrc/skins/native/cond.c   |  127 +++++++++++++++++++++----------
 ksrc/skins/native/event.c  |  153 +++++++++++++++++++++++++------------
 ksrc/skins/native/heap.c   |  159 ++++++++++++++++++++++++++------------
 ksrc/skins/native/intr.c   |  156 +++++++++++++++++++++++++-------------
 ksrc/skins/native/module.c |    9 +--
 ksrc/skins/native/mutex.c  |  166 +++++++++++++++++++++++++++-------------
 ksrc/skins/native/pipe.c   |   40 ++++++----
 ksrc/skins/native/queue.c  |  158 +++++++++++++++++++++++++++-----------
 ksrc/skins/native/sem.c    |  148 +++++++++++++++++++++++++-----------
 12 files changed, 972 insertions(+), 473 deletions(-)

diff --git a/ksrc/nucleus/heap.c b/ksrc/nucleus/heap.c
index def742b..24d963d 100644
--- a/ksrc/nucleus/heap.c
+++ b/ksrc/nucleus/heap.c
@@ -159,7 +159,7 @@ static int vfile_show(struct xnvfile_snapshot_iterator *it, 
void *data)
                               p->usable_mem,
                               p->used_mem,
                               p->page_size,
-                              sizeof(p->label),
+                              (int)sizeof(p->label),
                               p->label);
        return 0;
 }
diff --git a/ksrc/skins/native/alarm.c b/ksrc/skins/native/alarm.c
index 1130dfb..76bce0d 100644
--- a/ksrc/skins/native/alarm.c
+++ b/ksrc/skins/native/alarm.c
@@ -45,67 +45,119 @@
 
 #ifdef CONFIG_PROC_FS
 
-static int __alarm_read_proc(char *page,
-                            char **start,
-                            off_t off, int count, int *eof, void *data)
+struct vfile_priv {
+       int nrdata;
+       struct xnpholder *curr;
+       RTIME interval;
+       unsigned long expiries;
+};
+
+struct vfile_data {
+       char name[XNOBJECT_NAME_LEN];
+};
+
+static int vfile_rewind(struct xnvfile_snapshot_iterator *it)
 {
-       RT_ALARM *alarm = (RT_ALARM *)data;
-       char *p = page;
-       int len;
-       spl_t s;
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       RT_ALARM *alarm = xnvfile_priv(it->vfile);
 
-       xnlock_get_irqsave(&nklock, s);
+       alarm = xeno_h2obj_validate(alarm, XENO_ALARM_MAGIC, RT_ALARM);
+       if (alarm == NULL)
+               return -EIDRM;
 
-       p += sprintf(p, "interval=%Lu:expiries=%lu\n",
-                    rt_timer_tsc2ns(xntimer_interval(&alarm->timer_base)),
-                    alarm->expiries);
+       priv->nrdata = xnsynch_nsleepers(&alarm->synch_base);
+       priv->curr = getheadpq(xnsynch_wait_queue(&alarm->synch_base));
+       priv->interval = rt_timer_tsc2ns(xntimer_interval(&alarm->timer_base));
+       priv->expiries = alarm->expiries;
 
-#ifdef CONFIG_XENO_OPT_PERVASIVE
-       {
-               xnpholder_t *holder =
-                   getheadpq(xnsynch_wait_queue(&alarm->synch_base));
-
-               while (holder) {
-                       xnthread_t *sleeper = link2thread(holder, plink);
-                       p += sprintf(p, "+%s\n", xnthread_name(sleeper));
-                       holder =
-                           nextpq(xnsynch_wait_queue(&alarm->synch_base),
-                                  holder);
-               }
-       }
-#endif /* CONFIG_XENO_OPT_PERVASIVE */
+       return 0;
+}
 
-       xnlock_put_irqrestore(&nklock, s);
+static void *vfile_begin(struct xnvfile_snapshot_iterator *it)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
 
-       len = (p - page) - off;
-       if (len <= off + count)
-               *eof = 1;
-       *start = page + off;
-       if (len > count)
-               len = count;
-       if (len < 0)
-               len = 0;
+       if (priv->nrdata == 0)
+               /* No output beside the header. */
+               return VFILE_SEQ_EMPTY;
 
-       return len;
+       return kmalloc(priv->nrdata * sizeof(struct vfile_data),
+                      GFP_KERNEL);
 }
 
-extern xnptree_t __native_ptree;
+static void vfile_end(struct xnvfile_snapshot_iterator *it, void *buf)
+{
+       kfree(buf);
+}
 
-static xnpnode_t __alarm_pnode = {
+static int vfile_next(struct xnvfile_snapshot_iterator *it, void *data)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       RT_ALARM *alarm = xnvfile_priv(it->vfile);
+       struct vfile_data *p = data;
+       struct xnthread *thread;
+
+       if (priv->curr == NULL)
+               return 0;       /* We are done. */
+
+       /* Fetch current waiter, advance list cursor. */
+       thread = link2thread(priv->curr, plink);
+       priv->curr = nextpq(xnsynch_wait_queue(&alarm->synch_base),
+                           priv->curr);
+       /* Collect thread name to be output in ->show(). */
+       strncpy(p->name, xnthread_name(thread), sizeof(p->name));
+
+       return 1;
+}
+
+static int vfile_show(struct xnvfile_snapshot_iterator *it, void *data)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       struct vfile_data *p = data;
+
+       if (p == NULL) {        /* Dump header. */
+               xnvfile_printf(it, "%8s  %s\n", "INTERVAL", "EXPIRIES");
+               xnvfile_printf(it, "%8Lu  %lu\n",
+                              priv->interval, priv->expiries);
+               if (priv->nrdata > 0)
+                       /* Alarm is pended -- dump waiters */
+                       xnvfile_printf(it, "------------------\n");
+       } else
+               xnvfile_printf(it, "%.*s\n",
+                              (int)sizeof(p->name), p->name);
 
-       .dir = NULL,
-       .type = "alarms",
-       .entries = 0,
-       .read_proc = &__alarm_read_proc,
-       .write_proc = NULL,
-       .root = &__native_ptree,
+       return 0;
+}
+
+static struct xnvfile_snapshot_ops vfile_ops = {
+       .rewind = vfile_rewind,
+       .begin = vfile_begin,
+       .next = vfile_next,
+       .end = vfile_end,
+       .show = vfile_show,
 };
 
-#else /* !CONFIG_PROC_FS */
+extern struct xnptree __native_ptree;
+
+static struct xnpnode_file __alarm_pnode = {
+       .node = {
+               .dirname = "alarms",
+               .root = &__native_ptree,
+               .ops = &xnregistry_vfile_ops,
+       },
+       .vfile = {
+               .privsz = sizeof(struct vfile_priv),
+               .datasz = sizeof(struct vfile_data),
+               .ops = &vfile_ops,
+       },
+};
 
-static xnpnode_t __alarm_pnode = {
+#else /* !CONFIG_PROC_FS */
 
-       .type = "alarms"
+static struct xnpnode_file __alarm_pnode = {
+       .node = {
+               .dirname = "alarms",
+       },
 };
 
 #endif /* !CONFIG_PROC_FS */
@@ -226,7 +278,7 @@ int rt_alarm_create(RT_ALARM *alarm,
                 * handles to half-baked objects...
                 */
                err = xnregistry_enter((*name) ? alarm->name : "", alarm,
-                                      &alarm->handle, &__alarm_pnode);
+                                      &alarm->handle, &__alarm_pnode.node);
                if (err)
                        rt_alarm_delete(alarm);
 
diff --git a/ksrc/skins/native/buffer.c b/ksrc/skins/native/buffer.c
index 8aca559..5f281d6 100644
--- a/ksrc/skins/native/buffer.c
+++ b/ksrc/skins/native/buffer.c
@@ -50,81 +50,140 @@
 
 #ifdef CONFIG_PROC_FS
 
-static int __buffer_read_proc(char *page,
-                             char **start,
-                             off_t off, int count, int *eof, void *data)
-{
-       RT_BUFFER *bf = (RT_BUFFER *)data;
-       char *p = page;
-       int len;
-       spl_t s;
+struct vfile_priv {
+       int nrdata;
+       struct xnpholder *curr;
+       int mode;
+       size_t bufsz;
+       size_t fillsz;
+       int input;
+};
 
-       xnlock_get_irqsave(&nklock, s);
+struct vfile_data {
+       char name[XNOBJECT_NAME_LEN];
+       int input;
+};
 
-       p += sprintf(p, "type=%s:size=%zu:used=%zu\n",
-                    bf->mode & B_PRIO ? "PRIO" : "FIFO",
-                    bf->bufsz,
-                    bf->fillsz);
+static int vfile_rewind(struct xnvfile_snapshot_iterator *it)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       RT_BUFFER *bf = xnvfile_priv(it->vfile);
 
-       if (xnsynch_nsleepers(&bf->isynch_base) > 0) {
-               xnpholder_t *holder;
+       bf = xeno_h2obj_validate(bf, XENO_BUFFER_MAGIC, RT_BUFFER);
+       if (bf == NULL)
+               return -EIDRM;
+
+       priv->nrdata = xnsynch_nsleepers(&bf->isynch_base) +
+               xnsynch_nsleepers(&bf->osynch_base);
+       /* Start collecting records from the input wait side. */
+       priv->curr = getheadpq(xnsynch_wait_queue(&bf->isynch_base));
+       priv->mode = bf->mode;
+       priv->bufsz = bf->bufsz;
+       priv->fillsz = bf->fillsz;
+       priv->input = 1;
 
-               holder = getheadpq(xnsynch_wait_queue(&bf->osynch_base));
+       return 0;
+}
 
-               while (holder) {
-                       xnthread_t *sleeper = link2thread(holder, plink);
-                       p += sprintf(p, "+%s (input)\n", 
xnthread_name(sleeper));
-                       holder =
-                           nextpq(xnsynch_wait_queue(&bf->isynch_base),
-                                  holder);
-               }
-       }
+static void *vfile_begin(struct xnvfile_snapshot_iterator *it)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
 
-       if (xnsynch_nsleepers(&bf->osynch_base) > 0) {
-               xnpholder_t *holder;
+       if (priv->nrdata == 0)
+               /* No output beside the header. */
+               return VFILE_SEQ_EMPTY;
 
-               holder = getheadpq(xnsynch_wait_queue(&bf->osynch_base));
+       return kmalloc(priv->nrdata * sizeof(struct vfile_data),
+                      GFP_KERNEL);
+}
 
-               while (holder) {
-                       xnthread_t *sleeper = link2thread(holder, plink);
-                       p += sprintf(p, "+%s (output)\n", 
xnthread_name(sleeper));
-                       holder =
-                           nextpq(xnsynch_wait_queue(&bf->osynch_base),
-                                  holder);
-               }
-       }
+static void vfile_end(struct xnvfile_snapshot_iterator *it, void *buf)
+{
+       kfree(buf);
+}
 
-       xnlock_put_irqrestore(&nklock, s);
+static int vfile_next(struct xnvfile_snapshot_iterator *it, void *data)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       RT_BUFFER *bf = xnvfile_priv(it->vfile);
+       struct vfile_data *p = data;
+       struct xnthread *thread;
+       struct xnpqueue *waitq;
+
+       if (priv->curr == NULL) { /* Attempt to switch queues. */
+               if (!priv->input)
+                       /* Finished output side, we are done. */
+                       return 0;
+               priv->input = 0;
+               waitq = xnsynch_wait_queue(&bf->osynch_base);
+               priv->curr = getheadpq(waitq);
+               if (priv->curr == NULL)
+                       return 0;
+       } else
+               waitq = priv->input ? xnsynch_wait_queue(&bf->isynch_base) :
+                       xnsynch_wait_queue(&bf->osynch_base);
+
+       /* Fetch current waiter, advance list cursor. */
+       thread = link2thread(priv->curr, plink);
+       priv->curr = nextpq(waitq, priv->curr);
+       /* Collect thread name to be output in ->show(). */
+       strncpy(p->name, xnthread_name(thread), sizeof(p->name));
+       p->input = priv->input;
+
+       return 1;
+}
 
-       len = (p - page) - off;
-       if (len <= off + count)
-               *eof = 1;
-       *start = page + off;
-       if (len > count)
-               len = count;
-       if (len < 0)
-               len = 0;
+static int vfile_show(struct xnvfile_snapshot_iterator *it, void *data)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       struct vfile_data *p = data;
+
+       if (p == NULL) {        /* Dump header. */
+               xnvfile_printf(it, "%4s  %9s  %9s\n",
+                              "TYPE", "TOTALMEM", "USEDMEM");
+               xnvfile_printf(it, "%s  %9Zu  %9Zu\n",
+                              priv->mode & B_PRIO ? "PRIO" : "FIFO",
+                              priv->bufsz, priv->fillsz);
+               if (priv->nrdata > 0)
+                       /* Alarm is pended -- dump waiters */
+                       xnvfile_printf(it, "\n%3s  %s\n", "WAY", "WAITER");
+       } else
+               xnvfile_printf(it, "%3s  %.*s\n",
+                              p->input ? "in" : "out",
+                              (int)sizeof(p->name), p->name);
 
-       return len;
+       return 0;
 }
 
-extern xnptree_t __native_ptree;
-
-static xnpnode_t __buffer_pnode = {
+static struct xnvfile_snapshot_ops vfile_ops = {
+       .rewind = vfile_rewind,
+       .begin = vfile_begin,
+       .next = vfile_next,
+       .end = vfile_end,
+       .show = vfile_show,
+};
 
-       .dir = NULL,
-       .type = "buffers",
-       .entries = 0,
-       .read_proc = &__buffer_read_proc,
-       .write_proc = NULL,
-       .root = &__native_ptree,
+extern struct xnptree __native_ptree;
+
+static struct xnpnode_file __buffer_pnode = {
+       .node = {
+               .dirname = "buffers",
+               .root = &__native_ptree,
+               .ops = &xnregistry_vfile_ops,
+       },
+       .vfile = {
+               .privsz = sizeof(struct vfile_priv),
+               .datasz = sizeof(struct vfile_data),
+               .ops = &vfile_ops,
+       },
 };
 
 #else /* !CONFIG_PROC_FS */
 
-static xnpnode_t __buffer_pnode = {
-
-       .type = "buffers"
+static struct xnpnode_file __buffer_pnode = {
+       .node = {
+               .dirname = "buffers",
+       },
 };
 
 #endif /* !CONFIG_PROC_FS */
@@ -234,7 +293,7 @@ int rt_buffer_create(RT_BUFFER *bf, const char *name, 
size_t bufsz, int mode)
         */
        if (name) {
                ret = xnregistry_enter(bf->name, bf, &bf->handle,
-                                      &__buffer_pnode);
+                                      &__buffer_pnode.node);
 
                if (ret)
                        rt_buffer_delete(bf);
diff --git a/ksrc/skins/native/cond.c b/ksrc/skins/native/cond.c
index 86f83ff..53c51ee 100644
--- a/ksrc/skins/native/cond.c
+++ b/ksrc/skins/native/cond.c
@@ -50,64 +50,107 @@
 
 #ifdef CONFIG_PROC_FS
 
-static int __cond_read_proc(char *page,
-                           char **start,
-                           off_t off, int count, int *eof, void *data)
+struct vfile_priv {
+       int nrdata;
+       struct xnpholder *curr;
+};
+
+struct vfile_data {
+       char name[XNOBJECT_NAME_LEN];
+};
+
+static int vfile_rewind(struct xnvfile_snapshot_iterator *it)
 {
-       RT_COND *cond = (RT_COND *)data;
-       char *p = page;
-       int len;
-       spl_t s;
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       RT_COND *cond = xnvfile_priv(it->vfile);
 
-       xnlock_get_irqsave(&nklock, s);
+       cond = xeno_h2obj_validate(cond, XENO_COND_MAGIC, RT_COND);
+       if (cond == NULL)
+               return -EIDRM;
 
-       if (xnsynch_nsleepers(&cond->synch_base) > 0) {
-               xnpholder_t *holder;
+       priv->nrdata = xnsynch_nsleepers(&cond->synch_base);
+       priv->curr = getheadpq(xnsynch_wait_queue(&cond->synch_base));
 
-               /* Pended condvar -- dump waiters. */
+       return 0;
+}
 
-               holder = getheadpq(xnsynch_wait_queue(&cond->synch_base));
+static void *vfile_begin(struct xnvfile_snapshot_iterator *it)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
 
-               while (holder) {
-                       xnthread_t *sleeper = link2thread(holder, plink);
-                       p += sprintf(p, "+%s\n", xnthread_name(sleeper));
-                       holder =
-                           nextpq(xnsynch_wait_queue(&cond->synch_base),
-                                  holder);
-               }
-       }
+       if (priv->nrdata == 0)
+               /* No output beside the header. */
+               return VFILE_SEQ_EMPTY;
 
-       xnlock_put_irqrestore(&nklock, s);
+       return kmalloc(priv->nrdata * sizeof(struct vfile_data),
+                      GFP_KERNEL);
+}
 
-       len = (p - page) - off;
-       if (len <= off + count)
-               *eof = 1;
-       *start = page + off;
-       if (len > count)
-               len = count;
-       if (len < 0)
-               len = 0;
+static void vfile_end(struct xnvfile_snapshot_iterator *it, void *buf)
+{
+       kfree(buf);
+}
 
-       return len;
+static int vfile_next(struct xnvfile_snapshot_iterator *it, void *data)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       RT_COND *cond = xnvfile_priv(it->vfile);
+       struct vfile_data *p = data;
+       struct xnthread *thread;
+
+       if (priv->curr == NULL)
+               return 0;       /* We are done. */
+
+       /* Fetch current waiter, advance list cursor. */
+       thread = link2thread(priv->curr, plink);
+       priv->curr = nextpq(xnsynch_wait_queue(&cond->synch_base),
+                           priv->curr);
+       /* Collect thread name to be output in ->show(). */
+       strncpy(p->name, xnthread_name(thread), sizeof(p->name));
+
+       return 1;
 }
 
-extern xnptree_t __native_ptree;
+static int vfile_show(struct xnvfile_snapshot_iterator *it, void *data)
+{
+       struct vfile_data *p = data;
 
-static xnpnode_t __cond_pnode = {
+       if (p)  /* No header */
+               xnvfile_printf(it, "%.*s\n",
+                              (int)sizeof(p->name), p->name);
 
-       .dir = NULL,
-       .type = "condvars",
-       .entries = 0,
-       .read_proc = &__cond_read_proc,
-       .write_proc = NULL,
-       .root = &__native_ptree,
+       return 0;
+}
+
+static struct xnvfile_snapshot_ops vfile_ops = {
+       .rewind = vfile_rewind,
+       .begin = vfile_begin,
+       .next = vfile_next,
+       .end = vfile_end,
+       .show = vfile_show,
 };
 
-#else /* !CONFIG_PROC_FS */
+extern struct xnptree __native_ptree;
+
+static struct xnpnode_file __cond_pnode = {
+       .node = {
+               .dirname = "condvars",
+               .root = &__native_ptree,
+               .ops = &xnregistry_vfile_ops,
+       },
+       .vfile = {
+               .privsz = sizeof(struct vfile_priv),
+               .datasz = sizeof(struct vfile_data),
+               .ops = &vfile_ops,
+       },
+};
 
-static xnpnode_t __cond_pnode = {
+#else /* !CONFIG_PROC_FS */
 
-       .type = "condvars"
+static struct xnpnode_file __cond_pnode = {
+       .node = {
+               .dirname = "condvars",
+       },
 };
 
 #endif /* !CONFIG_PROC_FS */
@@ -181,7 +224,7 @@ int rt_cond_create(RT_COND *cond, const char *name)
         */
        if (name) {
                err = xnregistry_enter(cond->name, cond, &cond->handle,
-                                      &__cond_pnode);
+                                      &__cond_pnode.node);
 
                if (err)
                        rt_cond_delete(cond);
diff --git a/ksrc/skins/native/event.c b/ksrc/skins/native/event.c
index 5b2a8b5..e4ef387 100644
--- a/ksrc/skins/native/event.c
+++ b/ksrc/skins/native/event.c
@@ -47,72 +47,127 @@
 
 #ifdef CONFIG_PROC_FS
 
-static int __event_read_proc(char *page,
-                            char **start,
-                            off_t off, int count, int *eof, void *data)
+struct vfile_priv {
+       int nrdata;
+       struct xnpholder *curr;
+       unsigned long value;
+};
+
+struct vfile_data {
+       int mode;
+       unsigned long mask;
+       char name[XNOBJECT_NAME_LEN];
+};
+
+static int vfile_rewind(struct xnvfile_snapshot_iterator *it)
 {
-       RT_EVENT *event = (RT_EVENT *)data;
-       char *p = page;
-       int len;
-       spl_t s;
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       RT_EVENT *event = xnvfile_priv(it->vfile);
 
-       xnlock_get_irqsave(&nklock, s);
+       event = xeno_h2obj_validate(event, XENO_EVENT_MAGIC, RT_EVENT);
+       if (event == NULL)
+               return -EIDRM;
 
-       p += sprintf(p, "=0x%lx\n", event->value);
+       priv->nrdata = xnsynch_nsleepers(&event->synch_base);
+       priv->curr = getheadpq(xnsynch_wait_queue(&event->synch_base));
+       priv->value = event->value;
 
-       if (xnsynch_nsleepers(&event->synch_base) > 0) {
-               xnpholder_t *holder;
+       return 0;
+}
 
-               /* Pended event -- dump waiters. */
+static void *vfile_begin(struct xnvfile_snapshot_iterator *it)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
 
-               holder = getheadpq(xnsynch_wait_queue(&event->synch_base));
+       if (priv->nrdata == 0)
+               /* No output beside the header. */
+               return VFILE_SEQ_EMPTY;
 
-               while (holder) {
-                       xnthread_t *sleeper = link2thread(holder, plink);
-                       RT_TASK *task = thread2rtask(sleeper);
-                       const char *mode =
-                           (task->wait_args.event.
-                            mode & EV_ANY) ? "any" : "all";
-                       unsigned long mask = task->wait_args.event.mask;
-                       p += sprintf(p, "+%s (mask=0x%lx, %s)\n",
-                                    xnthread_name(sleeper), mask, mode);
-                       holder =
-                           nextpq(xnsynch_wait_queue(&event->synch_base),
-                                  holder);
-               }
-       }
+       return kmalloc(priv->nrdata * sizeof(struct vfile_data),
+                      GFP_KERNEL);
+}
 
-       xnlock_put_irqrestore(&nklock, s);
+static void vfile_end(struct xnvfile_snapshot_iterator *it, void *buf)
+{
+       kfree(buf);
+}
+
+static int vfile_next(struct xnvfile_snapshot_iterator *it, void *data)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       RT_EVENT *event = xnvfile_priv(it->vfile);
+       struct vfile_data *p = data;
+       struct xnthread *thread;
+       RT_TASK *task;
+
+       priv->value = event->value; /* Refresh as we collect. */
+
+       if (priv->curr == NULL)
+               return 0;       /* We are done. */
 
-       len = (p - page) - off;
-       if (len <= off + count)
-               *eof = 1;
-       *start = page + off;
-       if (len > count)
-               len = count;
-       if (len < 0)
-               len = 0;
+       /* Fetch current waiter, advance list cursor. */
+       thread = link2thread(priv->curr, plink);
+       priv->curr = nextpq(xnsynch_wait_queue(&event->synch_base),
+                           priv->curr);
 
-       return len;
+       /* Collect thread name to be output in ->show(). */
+       strncpy(p->name, xnthread_name(thread), sizeof(p->name));
+       task = thread2rtask(thread);
+       p->mode = task->wait_args.event.mode;
+       p->mask = task->wait_args.event.mask;
+
+       return 1;
 }
 
-extern xnptree_t __native_ptree;
+static int vfile_show(struct xnvfile_snapshot_iterator *it, void *data)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       struct vfile_data *p = data;
+
+       if (p == NULL) {        /* Dump header. */
+               /* Always dump current event mask value. */
+               xnvfile_printf(it, "=0x%lx\n", priv->value);
+               if (priv->nrdata > 0)
+                       xnvfile_printf(it, "\n%10s  %4s  %s\n",
+                                      "MASK", "MODE", "WAITER");
+       } else
+               xnvfile_printf(it, "0x%-8lx  %4s  %.*s\n",
+                              p->mask,
+                              p->mode & EV_ANY ? "any" : "all",
+                              (int)sizeof(p->name), p->name);
 
-static xnpnode_t __event_pnode = {
+       return 0;
+}
 
-       .dir = NULL,
-       .type = "events",
-       .entries = 0,
-       .read_proc = &__event_read_proc,
-       .write_proc = NULL,
-       .root = &__native_ptree,
+static struct xnvfile_snapshot_ops vfile_ops = {
+       .rewind = vfile_rewind,
+       .begin = vfile_begin,
+       .next = vfile_next,
+       .end = vfile_end,
+       .show = vfile_show,
 };
 
-#else /* !CONFIG_PROC_FS */
+extern struct xnptree __native_ptree;
+
+static struct xnpnode_file __event_pnode = {
+       .node = {
+               .dirname = "events",
+               .root = &__native_ptree,
+               .ops = &xnregistry_vfile_ops,
+       },
+       .vfile = {
+               .privsz = sizeof(struct vfile_priv),
+               .datasz = sizeof(struct vfile_data),
+               .ops = &vfile_ops,
+       },
+};
 
-static xnpnode_t __event_pnode = {
+#else /* !CONFIG_PROC_FS */
 
-       .type = "events"
+static struct xnpnode_file __event_pnode = {
+       .node = {
+               .dirname = "events",
+       },
 };
 
 #endif /* !CONFIG_PROC_FS */
@@ -205,7 +260,7 @@ int rt_event_create(RT_EVENT *event,
         */
        if (name) {
                err = xnregistry_enter(event->name, event, &event->handle,
-                                      &__event_pnode);
+                                      &__event_pnode.node);
 
                if (err)
                        rt_event_delete(event);
diff --git a/ksrc/skins/native/heap.c b/ksrc/skins/native/heap.c
index 2a5de8c..d8983c6 100644
--- a/ksrc/skins/native/heap.c
+++ b/ksrc/skins/native/heap.c
@@ -51,73 +51,130 @@
 
 #ifdef CONFIG_PROC_FS
 
-static int __heap_read_proc(char *page,
-                           char **start,
-                           off_t off, int count, int *eof, void *data)
-{
-       RT_HEAP *heap = (RT_HEAP *)data;
-       char *p = page;
-       int len;
-       spl_t s;
+struct vfile_priv {
+       int nrdata;
+       struct xnpholder *curr;
+       int mode;
+       size_t usable_mem;
+       size_t used_mem;
+       int nrmaps;
+};
 
-       p += sprintf(p, "type=%s:size=%lu:used=%lu:numaps=%lu\n",
-                    (heap->mode & H_SHARED) == H_SHARED ? "shared" :
-                    (heap->mode & H_MAPPABLE) ? "mappable" : "kernel",
-                    xnheap_usable_mem(&heap->heap_base),
-                    xnheap_used_mem(&heap->heap_base),
-                    heap->heap_base.archdep.numaps);
+struct vfile_data {
+       char name[XNOBJECT_NAME_LEN];
+       size_t size;
+};
 
-       xnlock_get_irqsave(&nklock, s);
+static int vfile_rewind(struct xnvfile_snapshot_iterator *it)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       RT_HEAP *heap = xnvfile_priv(it->vfile);
 
-       if (xnsynch_nsleepers(&heap->synch_base) > 0) {
-               xnpholder_t *holder;
+       heap = xeno_h2obj_validate(heap, XENO_HEAP_MAGIC, RT_HEAP);
+       if (heap == NULL)
+               return -EIDRM;
 
-               /* Pended heap -- dump waiters. */
+       priv->nrdata = xnsynch_nsleepers(&heap->synch_base);
+       priv->curr = getheadpq(xnsynch_wait_queue(&heap->synch_base));
+       priv->mode = heap->mode;
+       priv->usable_mem = xnheap_usable_mem(&heap->heap_base);
+       priv->used_mem = xnheap_used_mem(&heap->heap_base);
+       priv->nrmaps = heap->heap_base.archdep.numaps;
 
-               holder = getheadpq(xnsynch_wait_queue(&heap->synch_base));
+       return 0;
+}
 
-               while (holder) {
-                       xnthread_t *sleeper = link2thread(holder, plink);
-                       size_t size = sleeper->wait_u.buffer.size;
-                       p += sprintf(p, "+%s (size=%zd)\n",
-                                    xnthread_name(sleeper), size);
-                       holder =
-                           nextpq(xnsynch_wait_queue(&heap->synch_base),
-                                  holder);
-               }
-       }
+static void *vfile_begin(struct xnvfile_snapshot_iterator *it)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
 
-       xnlock_put_irqrestore(&nklock, s);
+       if (priv->nrdata == 0)
+               /* No output beside the header. */
+               return VFILE_SEQ_EMPTY;
 
-       len = (p - page) - off;
-       if (len <= off + count)
-               *eof = 1;
-       *start = page + off;
-       if (len > count)
-               len = count;
-       if (len < 0)
-               len = 0;
+       return kmalloc(priv->nrdata * sizeof(struct vfile_data),
+                      GFP_KERNEL);
+}
 
-       return len;
+static void vfile_end(struct xnvfile_snapshot_iterator *it, void *buf)
+{
+       kfree(buf);
 }
 
-extern xnptree_t __native_ptree;
+static int vfile_next(struct xnvfile_snapshot_iterator *it, void *data)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       RT_HEAP *heap = xnvfile_priv(it->vfile);
+       struct vfile_data *p = data;
+       struct xnthread *thread;
+
+       if (priv->curr == NULL)
+               return 0;       /* We are done. */
+
+       /* Fetch current waiter, advance list cursor. */
+       thread = link2thread(priv->curr, plink);
+       priv->curr = nextpq(xnsynch_wait_queue(&heap->synch_base),
+                           priv->curr);
+       /* Collect thread info to be output in ->show(). */
+       strncpy(p->name, xnthread_name(thread), sizeof(p->name));
+       p->size = thread->wait_u.buffer.size;
+
+       return 1;
+}
 
-static xnpnode_t __heap_pnode = {
+static int vfile_show(struct xnvfile_snapshot_iterator *it, void *data)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       struct vfile_data *p = data;
+
+       if (p == NULL) {        /* Dump header. */
+               xnvfile_printf(it, "%5s  %9s  %9s  %s\n",
+                              "TYPE", "TOTALMEM", "USEDMEM", "NRMAPS");
+               xnvfile_printf(it, "%5s  %9Zu  %9Zu  %d\n",
+                              priv->mode & H_SHARED ? "shared" :
+                              (priv->mode & H_MAPPABLE) ? "mappable" : 
"kernel",
+                              priv->usable_mem,
+                              priv->used_mem,
+                              priv->nrmaps);
+               if (priv->nrdata > 0)
+                       /* Queue is pended -- dump waiters */
+                       xnvfile_printf(it, "\n%7s  %s\n", "REQSZ", "WAITER");
+       } else
+               xnvfile_printf(it, "%7Zu  %.*s\n",
+                              p->size, (int)sizeof(p->name), p->name);
 
-       .dir = NULL,
-       .type = "heaps",
-       .entries = 0,
-       .read_proc = &__heap_read_proc,
-       .write_proc = NULL,
-       .root = &__native_ptree,
+       return 0;
+}
+
+static struct xnvfile_snapshot_ops vfile_ops = {
+       .rewind = vfile_rewind,
+       .begin = vfile_begin,
+       .next = vfile_next,
+       .end = vfile_end,
+       .show = vfile_show,
 };
 
-#else /* !CONFIG_PROC_FS */
+extern struct xnptree __native_ptree;
+
+static struct xnpnode_file __heap_pnode = {
+       .node = {
+               .dirname = "heaps",
+               .root = &__native_ptree,
+               .ops = &xnregistry_vfile_ops,
+       },
+       .vfile = {
+               .privsz = sizeof(struct vfile_priv),
+               .datasz = sizeof(struct vfile_data),
+               .ops = &vfile_ops,
+       },
+};
 
-static xnpnode_t __heap_pnode = {
+#else /* !CONFIG_PROC_FS */
 
-       .type = "heaps"
+static struct xnpnode_file __heap_pnode = {
+       .node = {
+               .dirname = "heap",
+       },
 };
 
 #endif /* !CONFIG_PROC_FS */
@@ -313,7 +370,7 @@ int rt_heap_create(RT_HEAP *heap, const char *name, size_t 
heapsize, int mode)
         */
        if (name) {
                err = xnregistry_enter(heap->name, heap, &heap->handle,
-                                      &__heap_pnode);
+                                      &__heap_pnode.node);
 
                if (err)
                        rt_heap_delete(heap);
diff --git a/ksrc/skins/native/intr.c b/ksrc/skins/native/intr.c
index a69bd46..810d55f 100644
--- a/ksrc/skins/native/intr.c
+++ b/ksrc/skins/native/intr.c
@@ -58,72 +58,122 @@ static unsigned long __intr_get_hits(RT_INTR *intr)
 
 #ifdef CONFIG_PROC_FS
 
-static int __intr_read_proc(char *page,
-                           char **start,
-                           off_t off, int count, int *eof, void *data)
-{
-       RT_INTR *intr = (RT_INTR *)data;
-       char *p = page;
-       int len;
-       spl_t s;
+struct vfile_priv {
+       int nrdata;
+       struct xnpholder *curr;
+       int mode;
+       unsigned long hits;
+       unsigned int pending;
+};
 
-       xnlock_get_irqsave(&nklock, s);
+struct vfile_data {
+       char name[XNOBJECT_NAME_LEN];
+};
 
-#ifdef CONFIG_XENO_OPT_PERVASIVE
-       {
-               xnpholder_t *holder;
+static int vfile_rewind(struct xnvfile_snapshot_iterator *it)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       RT_INTR *intr = xnvfile_priv(it->vfile);
 
-               p += sprintf(p, "hits=%lu, pending=%u, mode=0x%x\n",
-                            __intr_get_hits(intr), intr->pending,
-                            intr->mode);
+       intr = xeno_h2obj_validate(intr, XENO_INTR_MAGIC, RT_INTR);
+       if (intr == NULL)
+               return -EIDRM;
 
-               /* Pended interrupt -- dump waiters. */
+       priv->nrdata = xnsynch_nsleepers(&intr->synch_base);
+       priv->curr = getheadpq(xnsynch_wait_queue(&intr->synch_base));
+       priv->mode = intr->mode;
+       priv->hits = __intr_get_hits(intr);
+       priv->pending = intr->pending;
 
-               holder = getheadpq(xnsynch_wait_queue(&intr->synch_base));
+       return 0;
+}
 
-               while (holder) {
-                       xnthread_t *sleeper = link2thread(holder, plink);
-                       p += sprintf(p, "+%s\n", xnthread_name(sleeper));
-                       holder =
-                           nextpq(xnsynch_wait_queue(&intr->synch_base),
-                                  holder);
-               }
-       }
-#else /* !CONFIG_XENO_OPT_PERVASIVE */
-       p += sprintf(p, "hits=%lu\n", __intr_get_hits(intr));
-#endif /* CONFIG_XENO_OPT_PERVASIVE */
+static void *vfile_begin(struct xnvfile_snapshot_iterator *it)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
 
-       xnlock_put_irqrestore(&nklock, s);
+       if (priv->nrdata == 0)
+               /* No output beside the header. */
+               return VFILE_SEQ_EMPTY;
+
+       return kmalloc(priv->nrdata * sizeof(struct vfile_data),
+                      GFP_KERNEL);
+}
 
-       len = (p - page) - off;
-       if (len <= off + count)
-               *eof = 1;
-       *start = page + off;
-       if (len > count)
-               len = count;
-       if (len < 0)
-               len = 0;
+static void vfile_end(struct xnvfile_snapshot_iterator *it, void *buf)
+{
+       kfree(buf);
+}
 
-       return len;
+static int vfile_next(struct xnvfile_snapshot_iterator *it, void *data)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       RT_INTR *intr = xnvfile_priv(it->vfile);
+       struct vfile_data *p = data;
+       struct xnthread *thread;
+
+       if (priv->curr == NULL)
+               return 0;       /* We are done. */
+
+       /* Fetch current waiter, advance list cursor. */
+       thread = link2thread(priv->curr, plink);
+       priv->curr = nextpq(xnsynch_wait_queue(&intr->synch_base),
+                           priv->curr);
+       /* Collect thread name to be output in ->show(). */
+       strncpy(p->name, xnthread_name(thread), sizeof(p->name));
+
+       return 1;
 }
 
-extern xnptree_t __native_ptree;
+static int vfile_show(struct xnvfile_snapshot_iterator *it, void *data)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       struct vfile_data *p = data;
+
+       if (p == NULL) {        /* Dump header. */
+               xnvfile_printf(it, "%9s  %2s  %s\n",
+                              "HITS", "PENDING", "MODE");
+               xnvfile_printf(it, "%9lu  %u  0x%x\n",
+                              priv->hits, priv->pending, priv->mode);
+               if (priv->nrdata > 0)
+                       /* Alarm is pended -- dump waiters */
+                       xnvfile_printf(it, "-------------------\n");
+       } else
+               xnvfile_printf(it, "%.*s\n",
+                              sizeof(p->name), p->name);
+
+       return 0;
+}
 
-static xnpnode_t __intr_pnode = {
+static struct xnvfile_snapshot_ops vfile_ops = {
+       .rewind = vfile_rewind,
+       .begin = vfile_begin,
+       .next = vfile_next,
+       .end = vfile_end,
+       .show = vfile_show,
+};
 
-       .dir = NULL,
-       .type = "interrupts",
-       .entries = 0,
-       .read_proc = &__intr_read_proc,
-       .write_proc = NULL,
-       .root = &__native_ptree,
+extern struct xnptree __native_ptree;
+
+static struct xnpnode_file __intr_pnode = {
+       .node = {
+               .dirname = "interrupts",
+               .root = &__native_ptree,
+               .ops = &xnregistry_vfile_ops,
+       },
+       .vfile = {
+               .privsz = sizeof(struct vfile_priv),
+               .datasz = sizeof(struct vfile_data),
+               .ops = &vfile_ops,
+       },
 };
 
 #else /* !CONFIG_PROC_FS */
 
-static xnpnode_t __intr_pnode = {
-
-       .type = "interrupts"
+static struct xnpnode_file __intr_pnode = {
+       .node = {
+               .dirname = "interrupts",
+       },
 };
 
 #endif /* !CONFIG_PROC_FS */
@@ -288,7 +338,7 @@ int rt_intr_create(RT_INTR *intr,
         */
        if (!err && name)
                err = xnregistry_enter(intr->name, intr, &intr->handle,
-                                      &__intr_pnode);
+                                      &__intr_pnode.node);
        if (err)
                rt_intr_delete(intr);
 
diff --git a/ksrc/skins/native/module.c b/ksrc/skins/native/module.c
index 1a51bcf..60ca5aa 100644
--- a/ksrc/skins/native/module.c
+++ b/ksrc/skins/native/module.c
@@ -54,14 +54,7 @@ xntbase_t *__native_tbase;
 
 xeno_rholder_t __native_global_rholder;
 
-#ifdef CONFIG_PROC_FS
-xnptree_t __native_ptree = {
-
-       .dir = NULL,
-       .name = "native",
-       .entries = 0,
-};
-#endif /* CONFIG_PROC_FS */
+DEFINE_XNPTREE(__native_ptree, "native");
 
 int SKIN_INIT(native)
 {
diff --git a/ksrc/skins/native/mutex.c b/ksrc/skins/native/mutex.c
index 6cf7eb1..664e894 100644
--- a/ksrc/skins/native/mutex.c
+++ b/ksrc/skins/native/mutex.c
@@ -53,83 +53,141 @@
 
 #ifdef CONFIG_PROC_FS
 
-static int __mutex_read_proc(char *page,
-                            char **start,
-                            off_t off, int count, int *eof, void *data)
+struct vfile_priv {
+       int nrdata;
+       struct xnpholder *curr;
+       char owner[XNOBJECT_NAME_LEN];
+};
+
+struct vfile_data {
+       char name[XNOBJECT_NAME_LEN];
+};
+
+static int vfile_rewind(struct xnvfile_snapshot_iterator *it)
 {
-       RT_MUTEX *mutex = (RT_MUTEX *)data;
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       RT_MUTEX *mutex = xnvfile_priv(it->vfile);
+       struct xnthread *owner;
 #ifdef CONFIG_XENO_FASTSYNCH
        xnhandle_t lock_state;
-#endif /* CONFIG_XENO_FASTSYNCH */
-       xnthread_t *owner;
-       char *p = page;
-       int len;
-       spl_t s;
-
-       xnlock_get_irqsave(&nklock, s);
+#endif
+       mutex = xeno_h2obj_validate(mutex, XENO_MUTEX_MAGIC, RT_MUTEX);
+       if (mutex == NULL)
+               return -EIDRM;
 
-#ifndef CONFIG_XENO_FASTSYNCH
-       owner = xnsynch_owner(&mutex->synch_base);
-#else /* CONFIG_XENO_FASTSYNCH */
+#ifdef CONFIG_XENO_FASTSYNCH
        lock_state = xnarch_atomic_get(mutex->synch_base.fastlock);
-
        owner = (lock_state == XN_NO_HANDLE) ? NULL :
                xnthread_lookup(xnsynch_fast_mask_claimed(lock_state));
 
-       if (!owner && lock_state != XN_NO_HANDLE)
-               p += sprintf(p, "=<DAMAGED HANDLE!>");
+       if (owner == NULL && lock_state != XN_NO_HANDLE)
+               strncpy(priv->owner, "<DAMAGED HANDLE>",
+                       sizeof(priv->owner));
        else
-#endif /* CONFIG_XENO_FASTSYNCH */
-       if (owner) {
-               /* Locked mutex -- dump owner and waiters, if any. */
-               xnpholder_t *holder;
+#else /* !CONFIG_XENO_FASTSYNCH */
+       owner = xnsynch_owner(&mutex->synch_base);
+#endif /* !CONFIG_XENO_FASTSYNCH */
+       if (owner)
+               strncpy(priv->owner, xnthread_name(owner),
+                       sizeof(priv->owner));
+       else
+               *priv->owner = 0;
 
-               p += sprintf(p, "=locked by %s\n", xnthread_name(owner));
+       priv->nrdata = xnsynch_nsleepers(&mutex->synch_base);
+       priv->curr = getheadpq(xnsynch_wait_queue(&mutex->synch_base));
 
-               holder = getheadpq(xnsynch_wait_queue(&mutex->synch_base));
+       return 0;
+}
 
-               while (holder) {
-                       xnthread_t *sleeper = link2thread(holder, plink);
+static void *vfile_begin(struct xnvfile_snapshot_iterator *it)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
 
-                       p += sprintf(p, "+%s\n", xnthread_name(sleeper));
-                       holder = nextpq(xnsynch_wait_queue(&mutex->synch_base),
-                                       holder);
-               }
-       } else
-               /* Mutex unlocked. */
-               p += sprintf(p, "=unlocked\n");
+       if (priv->nrdata == 0)
+               /* No output beside the header. */
+               return VFILE_SEQ_EMPTY;
 
-       xnlock_put_irqrestore(&nklock, s);
+       return kmalloc(priv->nrdata * sizeof(struct vfile_data),
+                      GFP_KERNEL);
+}
 
-       len = (p - page) - off;
-       if (len <= off + count)
-               *eof = 1;
-       *start = page + off;
-       if (len > count)
-               len = count;
-       if (len < 0)
-               len = 0;
+static void vfile_end(struct xnvfile_snapshot_iterator *it, void *buf)
+{
+       kfree(buf);
+}
 
-       return len;
+static int vfile_next(struct xnvfile_snapshot_iterator *it, void *data)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       RT_MUTEX *mutex = xnvfile_priv(it->vfile);
+       struct vfile_data *p = data;
+       struct xnthread *thread;
+
+       if (priv->curr == NULL)
+               return 0;       /* We are done. */
+
+       /* Fetch current waiter, advance list cursor. */
+       thread = link2thread(priv->curr, plink);
+       priv->curr = nextpq(xnsynch_wait_queue(&mutex->synch_base),
+                           priv->curr);
+       /* Collect thread name to be output in ->show(). */
+       strncpy(p->name, xnthread_name(thread), sizeof(p->name));
+
+       return 1;
 }
 
-extern xnptree_t __native_ptree;
+static int vfile_show(struct xnvfile_snapshot_iterator *it, void *data)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       struct vfile_data *p = data;
+
+       if (p == NULL) {        /* Dump header. */
+               if (*priv->owner == 0)
+                       /* Unlocked mutex. */
+                       xnvfile_printf(it, "=unlocked\n");
+               else {
+                       xnvfile_printf(it, "=locked by %.*s\n",
+                                      (int)sizeof(priv->owner), priv->owner);
+                       if (priv->nrdata > 0)
+                               /* Mutex is contended -- dump waiters */
+                               xnvfile_printf(it, "--------------------\n");
+               }
+       } else
+               xnvfile_printf(it, "%.*s\n",
+                              (int)sizeof(p->name), p->name);
 
-static xnpnode_t __mutex_pnode = {
+       return 0;
+}
 
-       .dir = NULL,
-       .type = "mutexes",
-       .entries = 0,
-       .read_proc = &__mutex_read_proc,
-       .write_proc = NULL,
-       .root = &__native_ptree,
+static struct xnvfile_snapshot_ops vfile_ops = {
+       .rewind = vfile_rewind,
+       .begin = vfile_begin,
+       .next = vfile_next,
+       .end = vfile_end,
+       .show = vfile_show,
 };
 
-#else /* !CONFIG_PROC_FS */
+extern struct xnptree __native_ptree;
+
+static struct xnpnode_file __mutex_pnode = {
+       .node = {
+               .dirname = "mutexes",
+               .root = &__native_ptree,
+               .ops = &xnregistry_vfile_ops,
+       },
+       .vfile = {
+               .privsz = sizeof(struct vfile_priv),
+               .datasz = sizeof(struct vfile_data),
+               .ops = &vfile_ops,
+       },
+};
 
-static xnpnode_t __mutex_pnode = {
+#else /* !CONFIG_PROC_FS */
 
-       .type = "mutexes"
+static struct xnpnode_file __mutex_pnode = {
+       .node = {
+               .dirname = "mutexes",
+       },
 };
 
 #endif /* !CONFIG_PROC_FS */
@@ -166,7 +224,7 @@ int rt_mutex_create_inner(RT_MUTEX *mutex, const char *name,
         */
        if (name) {
                err = xnregistry_enter(mutex->name, mutex, &mutex->handle,
-                                      &__mutex_pnode);
+                                      &__mutex_pnode.node);
 
                if (err)
                        rt_mutex_delete_inner(mutex);
diff --git a/ksrc/skins/native/pipe.c b/ksrc/skins/native/pipe.c
index d756758..d8a1d91 100644
--- a/ksrc/skins/native/pipe.c
+++ b/ksrc/skins/native/pipe.c
@@ -54,28 +54,38 @@
 
 #ifdef CONFIG_PROC_FS
 
-static ssize_t __pipe_link_proc(char *buf, int count, void *data)
+static char *__pipe_link_target(void *obj)
 {
-       RT_PIPE *pipe = (RT_PIPE *)data;
-       return snprintf(buf, count, "/dev/rtp%d", pipe->minor);
-}
+       RT_PIPE *pipe = obj;
+       char *buf;
+
+       /* XXX: older kernels don't have kasprintf(). */
+       buf = kmalloc(32, GFP_KERNEL);
+       if (buf == NULL)
+               return buf;
+
+       snprintf(buf, 32, "/dev/rtp%d", pipe->minor);
 
-extern xnptree_t __native_ptree;
+       return buf;
+}
 
-static xnpnode_t __pipe_pnode = {
+extern struct xnptree __native_ptree;
 
-       .dir = NULL,
-       .type = "pipes",
-       .entries = 0,
-       .link_proc = &__pipe_link_proc,
-       .root = &__native_ptree,
+static struct xnpnode_link __pipe_pnode = {
+       .node = {
+               .dirname = "pipes",
+               .root = &__native_ptree,
+               .ops = &xnregistry_vlink_ops,
+       },
+       .target = __pipe_link_target,
 };
 
 #else /* !CONFIG_PROC_FS */
 
-static xnpnode_t __pipe_pnode = {
-
-       .type = "pipes"
+static struct xnpnode_link __pipe_pnode = {
+       .node = {
+               .dirname = "pipes",
+       },
 };
 
 #endif /* !CONFIG_PROC_FS */
@@ -352,7 +362,7 @@ int rt_pipe_create(RT_PIPE *pipe, const char *name, int 
minor, size_t poolsize)
         */
        if (name) {
                err = xnregistry_enter(pipe->name, pipe, &pipe->handle,
-                                      &__pipe_pnode);
+                                      &__pipe_pnode.node);
                if (err)
                        rt_pipe_delete(pipe);
        }
diff --git a/ksrc/skins/native/queue.c b/ksrc/skins/native/queue.c
index 6a71165..d97352f 100644
--- a/ksrc/skins/native/queue.c
+++ b/ksrc/skins/native/queue.c
@@ -49,68 +49,131 @@
 
 #ifdef CONFIG_PROC_FS
 
-static int __queue_read_proc(char *page,
-                            char **start,
-                            off_t off, int count, int *eof, void *data)
-{
-       RT_QUEUE *q = (RT_QUEUE *)data;
-       char *p = page;
-       int len;
-       spl_t s;
+struct vfile_priv {
+       int nrdata;
+       struct xnpholder *curr;
+       int mode;
+       size_t usable_mem;
+       size_t used_mem;
+       size_t limit;
+       size_t count;
+};
 
-       p += sprintf(p, "type=%s:poolsz=%lu:usedmem=%lu:limit=%d:mcount=%d\n",
-                    q->mode & Q_SHARED ? "shared" : "local",
-                    xnheap_usable_mem(&q->bufpool), 
xnheap_used_mem(&q->bufpool),
-                    q->qlimit, countq(&q->pendq));
+struct vfile_data {
+       char name[XNOBJECT_NAME_LEN];
+};
 
-       xnlock_get_irqsave(&nklock, s);
+static int vfile_rewind(struct xnvfile_snapshot_iterator *it)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       RT_QUEUE *q = xnvfile_priv(it->vfile);
 
-       if (xnsynch_nsleepers(&q->synch_base) > 0) {
-               xnpholder_t *holder;
+       q = xeno_h2obj_validate(q, XENO_QUEUE_MAGIC, RT_QUEUE);
+       if (q == NULL)
+               return -EIDRM;
 
-               /* Pended queue -- dump waiters. */
+       priv->nrdata = xnsynch_nsleepers(&q->synch_base);
+       priv->curr = getheadpq(xnsynch_wait_queue(&q->synch_base));
+       priv->mode = q->mode;
+       priv->usable_mem = xnheap_usable_mem(&q->bufpool);
+       priv->used_mem = xnheap_used_mem(&q->bufpool);
+       priv->limit = q->qlimit;
+       priv->count = countq(&q->pendq);
 
-               holder = getheadpq(xnsynch_wait_queue(&q->synch_base));
+       return 0;
+}
 
-               while (holder) {
-                       xnthread_t *sleeper = link2thread(holder, plink);
-                       p += sprintf(p, "+%s\n", xnthread_name(sleeper));
-                       holder =
-                           nextpq(xnsynch_wait_queue(&q->synch_base), holder);
-               }
-       }
+static void *vfile_begin(struct xnvfile_snapshot_iterator *it)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
 
-       xnlock_put_irqrestore(&nklock, s);
+       if (priv->nrdata == 0)
+               /* No output beside the header. */
+               return VFILE_SEQ_EMPTY;
 
-       len = (p - page) - off;
-       if (len <= off + count)
-               *eof = 1;
-       *start = page + off;
-       if (len > count)
-               len = count;
-       if (len < 0)
-               len = 0;
+       return kmalloc(priv->nrdata * sizeof(struct vfile_data),
+                      GFP_KERNEL);
+}
+
+static void vfile_end(struct xnvfile_snapshot_iterator *it, void *buf)
+{
+       kfree(buf);
+}
 
-       return len;
+static int vfile_next(struct xnvfile_snapshot_iterator *it, void *data)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       RT_QUEUE *q = xnvfile_priv(it->vfile);
+       struct vfile_data *p = data;
+       struct xnthread *thread;
+
+       if (priv->curr == NULL)
+               return 0;       /* We are done. */
+
+       /* Fetch current waiter, advance list cursor. */
+       thread = link2thread(priv->curr, plink);
+       priv->curr = nextpq(xnsynch_wait_queue(&q->synch_base),
+                           priv->curr);
+       /* Collect thread name to be output in ->show(). */
+       strncpy(p->name, xnthread_name(thread), sizeof(p->name));
+
+       return 1;
 }
 
-extern xnptree_t __native_ptree;
+static int vfile_show(struct xnvfile_snapshot_iterator *it, void *data)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       struct vfile_data *p = data;
+
+       if (p == NULL) {        /* Dump header. */
+               xnvfile_printf(it, "%5s  %9s  %9s  %6s  %s\n",
+                              "TYPE", "TOTALMEM", "USEDMEM",
+                              "QLIMIT", "MCOUNT");
+               xnvfile_printf(it, "%4s  %9Zu  %9Zu  %6Zu  %Zu\n",
+                              priv->mode & Q_SHARED ? "shared" : "local",
+                              priv->usable_mem,
+                              priv->used_mem,
+                              priv->limit,
+                              priv->count);
+               if (priv->nrdata > 0)
+                       /* Queue is pended -- dump waiters */
+                       xnvfile_printf(it, 
"-------------------------------------------\n");
+       } else
+               xnvfile_printf(it, "%.*s\n",
+                              (int)sizeof(p->name), p->name);
+
+       return 0;
+}
 
-static xnpnode_t __queue_pnode = {
+static struct xnvfile_snapshot_ops vfile_ops = {
+       .rewind = vfile_rewind,
+       .begin = vfile_begin,
+       .next = vfile_next,
+       .end = vfile_end,
+       .show = vfile_show,
+};
 
-       .dir = NULL,
-       .type = "queues",
-       .entries = 0,
-       .read_proc = &__queue_read_proc,
-       .write_proc = NULL,
-       .root = &__native_ptree,
+extern struct xnptree __native_ptree;
+
+static struct xnpnode_file __q_pnode = {
+       .node = {
+               .dirname = "queues",
+               .root = &__native_ptree,
+               .ops = &xnregistry_vfile_ops,
+       },
+       .vfile = {
+               .privsz = sizeof(struct vfile_priv),
+               .datasz = sizeof(struct vfile_data),
+               .ops = &vfile_ops,
+       },
 };
 
 #else /* !CONFIG_PROC_FS */
 
-static xnpnode_t __queue_pnode = {
-
-       .type = "queues"
+static struct xnpnode_file __q_pnode = {
+       .node = {
+               .dirname = "queues",
+       },
 };
 
 #endif /* !CONFIG_PROC_FS */
@@ -276,7 +339,8 @@ int rt_queue_create(RT_QUEUE *q,
         * handles to half-baked objects...
         */
        if (name) {
-               err = xnregistry_enter(q->name, q, &q->handle, &__queue_pnode);
+               err = xnregistry_enter(q->name, q,
+                                      &q->handle, &__q_pnode.node);
                if (err)
                        rt_queue_delete(q);
        }
diff --git a/ksrc/skins/native/sem.c b/ksrc/skins/native/sem.c
index 0afea09..3ab23ea 100644
--- a/ksrc/skins/native/sem.c
+++ b/ksrc/skins/native/sem.c
@@ -50,67 +50,125 @@
 
 #ifdef CONFIG_PROC_FS
 
-static int __sem_read_proc(char *page,
-                          char **start,
-                          off_t off, int count, int *eof, void *data)
+struct vfile_priv {
+       int nrdata;
+       struct xnpholder *curr;
+       unsigned long count;
+};
+
+struct vfile_data {
+       char name[XNOBJECT_NAME_LEN];
+};
+
+static int vfile_rewind(struct xnvfile_snapshot_iterator *it)
 {
-       RT_SEM *sem = (RT_SEM *)data;
-       char *p = page;
-       int len;
-       spl_t s;
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       RT_SEM *sem = xnvfile_priv(it->vfile);
 
-       xnlock_get_irqsave(&nklock, s);
+       sem = xeno_h2obj_validate(sem, XENO_SEM_MAGIC, RT_SEM);
+       if (sem == NULL)
+               return -EIDRM;
 
-       if (xnsynch_nsleepers(&sem->synch_base) == 0)
-               /* Idle/posted semaphore -- dump count. */
-               p += sprintf(p, "=%lu\n", sem->count);
-       else {
-               xnpholder_t *holder;
+       priv->nrdata = xnsynch_nsleepers(&sem->synch_base);
+       priv->curr = getheadpq(xnsynch_wait_queue(&sem->synch_base));
+       priv->count = sem->count;
 
-               /* Pended semaphore -- dump waiters. */
+       return 0;
+}
 
-               holder = getheadpq(xnsynch_wait_queue(&sem->synch_base));
+static void *vfile_begin(struct xnvfile_snapshot_iterator *it)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
 
-               while (holder) {
-                       xnthread_t *sleeper = link2thread(holder, plink);
-                       p += sprintf(p, "+%s\n", xnthread_name(sleeper));
-                       holder =
-                           nextpq(xnsynch_wait_queue(&sem->synch_base),
-                                  holder);
-               }
-       }
+       if (priv->nrdata == 0)
+               /* No output beside the header. */
+               return VFILE_SEQ_EMPTY;
 
-       xnlock_put_irqrestore(&nklock, s);
+       return kmalloc(priv->nrdata * sizeof(struct vfile_data),
+                      GFP_KERNEL);
+}
 
-       len = (p - page) - off;
-       if (len <= off + count)
-               *eof = 1;
-       *start = page + off;
-       if (len > count)
-               len = count;
-       if (len < 0)
-               len = 0;
+static void vfile_end(struct xnvfile_snapshot_iterator *it, void *buf)
+{
+       kfree(buf);
+}
 
-       return len;
+static int vfile_next(struct xnvfile_snapshot_iterator *it, void *data)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       RT_SEM *sem = xnvfile_priv(it->vfile);
+       struct vfile_data *p = data;
+       struct xnthread *thread;
+
+       /*
+        * Refresh the semaphore count as we get waiters, to reduce
+        * the odds for inconsistency (that value may change while
+        * collecting records, and we don't want to touch the revision
+        * tag each time that value changes).
+        */
+       priv->count = sem->count;
+
+       if (priv->curr == NULL)
+               return 0;       /* We are done. */
+
+       /* Fetch current waiter, advance list cursor. */
+       thread = link2thread(priv->curr, plink);
+       priv->curr = nextpq(xnsynch_wait_queue(&sem->synch_base),
+                           priv->curr);
+       /* Collect thread name to be output in ->show(). */
+       strncpy(p->name, xnthread_name(thread), sizeof(p->name));
+
+       return 1;
 }
 
-extern xnptree_t __native_ptree;
+static int vfile_show(struct xnvfile_snapshot_iterator *it, void *data)
+{
+       struct vfile_priv *priv = xnvfile_snapshot_iterator_priv(it);
+       struct vfile_data *p = data;
 
-static xnpnode_t __sem_pnode = {
+       if (p == NULL) {        /* Dump header. */
+               if (priv->nrdata == 0)
+                       /* Idle/posted semaphore -- just dump count. */
+                       xnvfile_printf(it, "=%lu\n", priv->count);
+               else
+                       /* Semaphore is contended -- dump waiters */
+                       xnvfile_printf(it, "------------\n");
+       } else
+               xnvfile_printf(it, "%.*s\n",
+                              (int)sizeof(p->name), p->name);
+
+       return 0;
+}
 
-       .dir = NULL,
-       .type = "semaphores",
-       .entries = 0,
-       .read_proc = &__sem_read_proc,
-       .write_proc = NULL,
-       .root = &__native_ptree,
+static struct xnvfile_snapshot_ops vfile_ops = {
+       .rewind = vfile_rewind,
+       .begin = vfile_begin,
+       .next = vfile_next,
+       .end = vfile_end,
+       .show = vfile_show,
 };
 
-#else /* !CONFIG_PROC_FS */
+extern struct xnptree __native_ptree;
+
+static struct xnpnode_file __sem_pnode = {
+       .node = {
+               .dirname = "semaphores",
+               .root = &__native_ptree,
+               .ops = &xnregistry_vfile_ops,
+       },
+       .vfile = {
+               .privsz = sizeof(struct vfile_priv),
+               .datasz = sizeof(struct vfile_data),
+               .ops = &vfile_ops,
+       },
+};
 
-static xnpnode_t __sem_pnode = {
+#else /* !CONFIG_PROC_FS */
 
-       .type = "semaphores"
+static struct xnpnode_file __sem_pnode = {
+       .node = {
+               .dirname = "semaphores",
+       },
 };
 
 #endif /* !CONFIG_PROC_FS */
@@ -204,7 +262,7 @@ int rt_sem_create(RT_SEM *sem, const char *name, unsigned 
long icount, int mode)
         */
        if (name) {
                err = xnregistry_enter(sem->name, sem, &sem->handle,
-                                      &__sem_pnode);
+                                      &__sem_pnode.node);
                if (err)
                        rt_sem_delete(sem);
        }


_______________________________________________
Xenomai-git mailing list
Xenomai-git@gna.org
https://mail.gna.org/listinfo/xenomai-git

Reply via email to