text: /*
   * Copyright (C) 2013 Philippe Gerum <rpm@xenomai.org>.
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
   */
  
  #include <sys/types.h>
  #include <fcntl.h>
  #include <unistd.h>
  #include <stdlib.h>
  #include <stdio.h>
  #include <errno.h>
  #include <cobalt/uapi/thread.h>
  #include "sysregfs.h"
  
  #ifdef CONFIG_XENO_PSHARED
  /*
   * This is a blunt copy of what we do in kernel space to produce this
   * status in /proc/xenomai/sched/threads. There are additional states
   * for a thread compared to Mercury, introduced by the dual kernel
   * (such as relaxed mode, mode switch trap, and priority boost).
   */
  char *format_thread_status(const struct thread_data *p, char *buf, size_t len)
  {
  	static const char labels[] = XNTHREAD_STATE_LABELS;
  	unsigned long mask;
  	int pos, c;
  	char *wp;
  
  	for (mask = p->status, pos = 0, wp = buf;
  	     mask != 0 && wp - buf < len - 2;	/* 1-letter label + \0 */
  	     mask >>= 1, pos++) {
  		if ((mask & 1) == 0)
  			continue;
  
  		c = labels[pos];
  
  		switch (1 << pos) {
  		case XNROOT:
  			c = 'R'; /* Always mark root as runnable. */
  			break;
  		case XNREADY:
  			if (p->status & XNROOT)
  				continue; /* Already reported on XNROOT. */
  			break;
  		case XNDELAY:
  			/*
  			 * Only report genuine delays here, not timed
  			 * waits for resources.
  			 */
  			if (p->status & XNPEND)
  				continue;
  			break;
  		case XNPEND:
  			/* Report timed waits with lowercase symbol. */
  			if (p->status & XNDELAY)
  				c |= 0x20;
  			break;
  		default:
  			if (c == '.')
  				continue;
  		}
  		*wp++ = c;
  	}
  
  	*wp = '\0';
  
  	return buf;
  }
  
  #else /* !CONFIG_XENO_PSHARED */
  
  /*
   * If we have no session information, fallback to reading
   * /proc/xenomai.
   */
  
  #define PROC_PULL_HANDLER(__name, __path)				\
  int open_ ## __name(struct fsobj *fsobj, void *priv)			\
  {									\
  	return pull_proc_data("/proc/xenomai/" __path, priv);		\
  }
  
  /*
   * Cobalt-specific helper to pull the /proc vfile data provided by the
   * nucleus over a fuse-managed vfile.
   */
  static int pull_proc_data(const char *path, struct fsobstack *o)
  {
  	int len;
  
  	fsobstack_init(o);
  	len = fsobstack_grow_file(o, path);
  	fsobstack_finish(o);
  
  	return len < 0 ? len : 0;
  }
  
  PROC_PULL_HANDLER(threads, "/sched/threads");
  PROC_PULL_HANDLER(heaps, "/heap");
  
  #endif /* !CONFIG_XENO_PSHARED */
  
  struct sysreg_fsdir sysreg_dirs[] = {
  	{
  		.path = NULL,
  	},
  };
  
  struct sysreg_fsfile sysreg_files[] = {
  	{
  		.path = "/threads",
  		.mode = O_RDONLY,
  		.ops = {
  			.open = open_threads,
  			.release = fsobj_obstack_release,
  			.read = fsobj_obstack_read
  		},
  	},
  	{
  		.path = "/heaps",
  		.mode = O_RDONLY,
  		.ops = {
  			.open = open_heaps,
  			.release = fsobj_obstack_release,
  			.read = fsobj_obstack_read
  		},
  	},
  	{
  		.path = "/version",
  		.mode = O_RDONLY,
  		.ops = {
  			.open = open_version,
  			.release = fsobj_obstack_release,
  			.read = fsobj_obstack_read
  		},
  	},
  	{
  		.path = NULL,
  	}
  };
  