bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH hurd 3/8] libports: implement the Hurd server introspection proto


From: Justus Winter
Subject: [PATCH hurd 3/8] libports: implement the Hurd server introspection protocol
Date: Thu, 23 Oct 2014 17:16:41 +0200

Add a compact and self-contained introspection server to libports.
Add functions to to label port buckets and classes.  Make it possible
to provide a function that given an object of a class, returns a
human-readable representation for it.

* libports/introspection.c: New file.
* libports/create-bucket.c (ports_label_bucket): New function.
* libports/create-class.c (ports_set_debug_info): Likewise.
* libports/manage-multithread.c (internal_demuxer): Trace messages if
desired.
* libports/manage-one-thread.c (internal_demuxer): Likewise.
* libports/ports.h (struct port_bucket): Add label.
(struct port_class): Add debug_info and label.
(ports_label_bucket): New declaration.
(ports_set_debug_info): Likewise.
* libports/Makefile (SRCS): Add introspection.c.
(OBJS): Add hurd_portServer.o.
---
 ext2fs/Makefile               |   3 +-
 fatfs/Makefile                |   3 +-
 isofs/Makefile                |   3 +-
 libports/Makefile             |   6 +-
 libports/create-bucket.c      |   7 ++
 libports/create-class.c       |  16 ++++
 libports/introspection.c      | 189 ++++++++++++++++++++++++++++++++++++++++++
 libports/manage-multithread.c |   9 ++
 libports/manage-one-thread.c  |  10 +++
 libports/ports.h              |  14 ++++
 tmpfs/Makefile                |   3 +-
 11 files changed, 256 insertions(+), 7 deletions(-)
 create mode 100644 libports/introspection.c

diff --git a/ext2fs/Makefile b/ext2fs/Makefile
index 8d2e68c..9d72fda 100644
--- a/ext2fs/Makefile
+++ b/ext2fs/Makefile
@@ -23,7 +23,8 @@ target = ext2fs
 SRCS = balloc.c dir.c ext2fs.c getblk.c hyper.c ialloc.c \
        inode.c pager.c pokel.c truncate.c storeinfo.c msg.c xinl.c
 OBJS = $(SRCS:.c=.o)
-HURDLIBS = diskfs pager iohelp fshelp store ports ihash shouldbeinlibc
+HURDLIBS = diskfs pager iohelp fshelp store ports ihash introspection \
+       shouldbeinlibc
 OTHERLIBS = -lpthread $(and $(HAVE_LIBBZ2),-lbz2) $(and $(HAVE_LIBZ),-lz)
 
 include ../Makeconf
diff --git a/fatfs/Makefile b/fatfs/Makefile
index 6224b64..e4f01ec 100644
--- a/fatfs/Makefile
+++ b/fatfs/Makefile
@@ -22,7 +22,8 @@ target = fatfs
 SRCS = inode.c main.c dir.c pager.c fat.c virt-inode.c node-create.c
 
 OBJS = $(SRCS:.c=.o)
-HURDLIBS = diskfs iohelp fshelp store pager ports ihash shouldbeinlibc
+HURDLIBS = diskfs iohelp fshelp store pager ports ihash introspection \
+       shouldbeinlibc
 OTHERLIBS = -lpthread $(and $(HAVE_LIBBZ2),-lbz2) $(and $(HAVE_LIBZ),-lz)
 
 include ../Makeconf
diff --git a/isofs/Makefile b/isofs/Makefile
index 6475c52..9e399bf 100644
--- a/isofs/Makefile
+++ b/isofs/Makefile
@@ -21,7 +21,8 @@ target = iso9660fs
 SRCS = inode.c main.c lookup.c pager.c rr.c
 
 OBJS = $(SRCS:.c=.o)
-HURDLIBS = diskfs iohelp fshelp store pager ports ihash shouldbeinlibc
+HURDLIBS = diskfs iohelp fshelp store pager ports ihash introspection \
+       shouldbeinlibc
 OTHERLIBS = -lpthread $(and $(HAVE_LIBBZ2),-lbz2) $(and $(HAVE_LIBZ),-lz)
 
 include ../Makeconf
diff --git a/libports/Makefile b/libports/Makefile
index 30da1c1..7832b1b 100644
--- a/libports/Makefile
+++ b/libports/Makefile
@@ -36,13 +36,13 @@ SRCS = create-bucket.c create-class.c \
  interrupt-operation.c interrupt-on-notify.c interrupt-notified-rpcs.c \
  dead-name.c create-port.c import-port.c default-uninhibitable-rpcs.c \
  claim-right.c transfer-right.c create-port-noinstall.c create-internal.c \
- interrupted.c
+ interrupted.c introspection.c
 
 installhdrs = ports.h
 
-HURDLIBS= ihash
+HURDLIBS= ihash introspection
 LDLIBS += -lpthread
-OBJS = $(SRCS:.c=.o) notifyServer.o interruptServer.o
+OBJS = $(SRCS:.c=.o) notifyServer.o interruptServer.o hurd_portServer.o
 
 MIGCOMSFLAGS = -prefix ports_
 MIGSFLAGS = -imacros $(srcdir)/mig-mutate.h
diff --git a/libports/create-bucket.c b/libports/create-bucket.c
index 2c5f1b6..51168cb 100644
--- a/libports/create-bucket.c
+++ b/libports/create-bucket.c
@@ -48,5 +48,12 @@ ports_create_bucket ()
 
   hurd_ihash_init (&ret->htable, offsetof (struct port_info, hentry));
   ret->rpcs = ret->flags = ret->count = 0;
+  ret->label = "unlabeled bucket";
   return ret;
 }
+
+/* Label BUCKET with LABEL.  */
+void ports_label_bucket (struct port_bucket *bucket, const char *label)
+{
+  bucket->label = label;
+}
diff --git a/libports/create-class.c b/libports/create-class.c
index 782f52b..8abf643 100644
--- a/libports/create-class.c
+++ b/libports/create-class.c
@@ -41,6 +41,22 @@ ports_create_class (void (*clean_routine)(void *),
   cl->rpcs = 0;
   cl->count = 0;
   cl->uninhibitable_rpcs = ports_default_uninhibitable_rpcs;
+  cl->debug_info = NULL;
+  cl->label = "unlabeled class";
+  cl->trace_port = MACH_PORT_NULL;
 
   return cl;
 }
+
+/* Label CLASS with LABEL.  Use DEBUG_INFO to format human-readable
+   information about a given object belonging to CLASS into an buffer,
+   or the default formatting function if DEBUG_INFO is NULL.  */
+void
+ports_label_class (struct port_class *class,
+                  const char *label,
+                  error_t (*debug_info) (const void *, char *, size_t))
+{
+  class->label = label;
+  if (debug_info)
+    class->debug_info = debug_info;
+}
diff --git a/libports/introspection.c b/libports/introspection.c
new file mode 100644
index 0000000..05aee92
--- /dev/null
+++ b/libports/introspection.c
@@ -0,0 +1,189 @@
+/* Hurd server introspection.
+
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   The GNU Hurd 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
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the GNU Hurd.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <error.h>
+#include <hurd/introspection.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ports.h"
+#include "hurd_port_U.h"
+
+/* We service introspection requests on this port.  */
+static mach_port_t introspection_port;
+
+/* We use a separate thread to service the introspection requests.  It
+   is a straight forward Mach server for the hurd_port protocol.  */
+static void *
+service_introspection_requests (void *arg)
+{
+  error_t err;
+
+  err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+                           &introspection_port);
+  if (err)
+    {
+      error (0, err, "mach_port_allocate");
+      return NULL;
+    }
+
+  err = mach_port_insert_right (mach_task_self (),
+                               introspection_port, introspection_port,
+                               MACH_MSG_TYPE_MAKE_SEND);
+  if (err)
+    {
+      error (0, err, "mach_port_insert_right");
+      return NULL;
+    }
+
+  err = introspection_set_port (mach_task_self (), introspection_port);
+  if (err)
+    {
+      error (0, err, "introspection_set_port");
+      return NULL;
+    }
+
+  /* XXX mig should emit this declaration.  */
+  boolean_t ports_hurd_port_server (mach_msg_header_t *InHeadP,
+                                   mach_msg_header_t *OutHeadP);
+
+  while (1)
+    mach_msg_server (ports_hurd_port_server, 0, introspection_port);
+
+  /* Not reached.  */
+  return NULL;
+}
+
+/* Start the introspection server before main is called.  */
+static void __attribute__ ((constructor))
+init (void)
+{
+  error_t err;
+
+  pthread_t thread;
+  pthread_attr_t attr;
+#define STACK_SIZE (64 * 1024)
+  pthread_attr_init (&attr);
+  pthread_attr_setstacksize (&attr, STACK_SIZE);
+#undef STACK_SIZE
+
+  err = pthread_create (&thread, &attr,
+                       service_introspection_requests, NULL);
+  if (err)
+    error (1, err, "pthread_create");
+  pthread_detach (thread);
+}
+
+/* Return the number of hard and weak references of the object
+   directly associated with the receive right NAME.
+
+   Return EINVAL if NAME does not denote a receive right managed by
+   the port-to-object mapper, or if the concept of reference counting
+   simply does not apply.  */
+error_t
+ports_S_hurd_port_get_refcounts (mach_port_t port,
+                                mach_port_t name,
+                                natural_t *hard,
+                                natural_t *weak)
+{
+  struct references result;
+  struct port_info *pi;
+
+  if (port != introspection_port)
+    return EOPNOTSUPP;
+
+  pi = ports_lookup_port (0, name, 0);
+  if (pi == NULL)
+    return EINVAL;
+
+  refcounts_references (&pi->refcounts, &result);
+
+  *hard = result.hard - 1;
+  *weak = result.weak;
+  ports_port_deref (pi);
+  return 0;
+}
+
+static error_t
+default_debug_info (const void *port, char *buffer, size_t size)
+{
+  const struct port_info *pi = port;
+  snprintf (buffer, size,
+           "bucket: %s, class: %s",
+           pi->bucket->label, pi->class->label);
+  return 0;
+}
+
+/* Return a compact, human-readable description of the object related
+   with the receive right NAME.
+
+   This description is meant for debugging purposes and should include
+   relevant internal state.  If possible, it should include
+   information that is meaningful in other contexts (like a file name,
+   or the inode number).
+
+   Return EINVAL if NAME does not denote a receive right managed by
+   the port-to-object mapper.  */
+error_t
+ports_S_hurd_port_debug_info (mach_port_t port,
+                             mach_port_t name,
+                             char *info)
+{
+  error_t err;
+  struct port_info *pi;
+
+  if (port != introspection_port)
+    return EOPNOTSUPP;
+
+  pi = ports_lookup_port (0, name, 0);
+  if (pi == NULL)
+    return EINVAL;
+
+  if (pi->class->debug_info)
+    err = pi->class->debug_info (pi, info, 1024 /* XXX */);
+  else
+    err = default_debug_info (pi, info, 1024 /* XXX */);
+  info[1023] = 0;
+
+  ports_port_deref (pi);
+  return err;
+}
+
+error_t
+ports_S_hurd_port_trace_class_rpcs (mach_port_t port,
+                                   mach_port_t name,
+                                   mach_port_t trace_port)
+{
+  struct port_info *pi;
+
+  if (port != introspection_port)
+    return EOPNOTSUPP;
+
+  pi = ports_lookup_port (0, name, 0);
+  if (pi == NULL)
+    return EINVAL;
+
+  if (MACH_PORT_VALID (pi->class->trace_port))
+    mach_port_deallocate (mach_task_self (), pi->class->trace_port);
+
+  pi->class->trace_port = trace_port;
+
+  return 0;
+}
diff --git a/libports/manage-multithread.c b/libports/manage-multithread.c
index 2067cba..a2024fa 100644
--- a/libports/manage-multithread.c
+++ b/libports/manage-multithread.c
@@ -21,6 +21,7 @@
 #include "ports.h"
 #include <assert.h>
 #include <error.h>
+#include <hurd/introspection.h>
 #include <stdio.h>
 #include <mach/message.h>
 #include <mach/thread_info.h>
@@ -165,6 +166,10 @@ ports_manage_port_operations_multithread (struct 
port_bucket *bucket,
       pi = ports_lookup_port (bucket, inp->msgh_local_port, 0);
       if (pi)
        {
+         mach_port_t trace_port = pi->class->trace_port;
+         if (__builtin_expect (MACH_PORT_VALID (trace_port), 0))
+           introspection_trace_message (trace_port, inp);
+
          error_t err = ports_begin_rpc (pi, inp->msgh_id, &link);
          if (err)
            {
@@ -181,6 +186,10 @@ ports_manage_port_operations_multithread (struct 
port_bucket *bucket,
              ports_end_rpc (pi, &link);
            }
          ports_port_deref (pi);
+
+         if (__builtin_expect (MACH_PORT_VALID (trace_port), 0)
+             && outp->RetCode != MIG_NO_REPLY)
+           introspection_trace_message (trace_port, outp);
        }
       else
        {
diff --git a/libports/manage-one-thread.c b/libports/manage-one-thread.c
index cbd2df7..659306f 100644
--- a/libports/manage-one-thread.c
+++ b/libports/manage-one-thread.c
@@ -18,6 +18,8 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
+#include <hurd/introspection.h>
+
 #include "ports.h"
 
 void
@@ -60,6 +62,10 @@ ports_manage_port_operations_one_thread (struct port_bucket 
*bucket,
       pi = ports_lookup_port (bucket, inp->msgh_local_port, 0);
       if (pi)
        {
+         mach_port_t trace_port = pi->class->trace_port;
+         if (__builtin_expect (MACH_PORT_VALID (trace_port), 0))
+           introspection_trace_message (trace_port, inp);
+
          err = ports_begin_rpc (pi, inp->msgh_id, &link);
          if (err)
            {
@@ -76,6 +82,10 @@ ports_manage_port_operations_one_thread (struct port_bucket 
*bucket,
              ports_end_rpc (pi, &link);
            }
          ports_port_deref (pi);
+
+         if (__builtin_expect (MACH_PORT_VALID (trace_port), 0)
+             && outp->RetCode != MIG_NO_REPLY)
+           introspection_trace_message (trace_port, outp);
        }
       else
        {
diff --git a/libports/ports.h b/libports/ports.h
index 652edb8..c962804 100644
--- a/libports/ports.h
+++ b/libports/ports.h
@@ -67,6 +67,7 @@ struct port_bucket
   int rpcs;
   int flags;
   int count;
+  const char *label;
 };
 /* FLAGS above are the following: */
 #define PORT_BUCKET_INHIBITED  PORTS_INHIBITED
@@ -82,7 +83,10 @@ struct port_class
   int count;
   void (*clean_routine) (void *);
   void (*dropweak_routine) (void *);
+  error_t (*debug_info) (const void *, char *, size_t);
   struct ports_msg_id_range *uninhibitable_rpcs;
+  const char *label;
+  mach_port_t trace_port;
 };
 /* FLAGS are the following: */
 #define PORT_CLASS_INHIBITED   PORTS_INHIBITED
@@ -151,6 +155,9 @@ extern struct ports_msg_id_range 
*ports_default_uninhibitable_rpcs;
 /* Create and return a new bucket. */
 struct port_bucket *ports_create_bucket (void);
 
+/* Label BUCKET with LABEL.  */
+void ports_label_bucket (struct port_bucket *bucket, const char *label);
+
 /* Create and return a new port class.  If nonzero, CLEAN_ROUTINE will
    be called for each allocated port object in this class when it is
    being destroyed.   If nonzero, DROPWEAK_ROUTINE will be called
@@ -160,6 +167,12 @@ struct port_bucket *ports_create_bucket (void);
 struct port_class *ports_create_class (void (*clean_routine)(void *),
                                       void (*dropweak_routine)(void *));
 
+/* Label CLASS with LABEL.  Use DEBUG_INFO to format human-readable
+   information about a given object belonging to CLASS into an buffer,
+   or the default formatting function if DEBUG_INFO is NULL.  */
+void ports_label_class (struct port_class *class, const char *label,
+                       error_t (*debug_info) (const void *, char *, size_t));
+
 /* Create and return in RESULT a new port in CLASS and BUCKET; SIZE bytes
    will be allocated to hold the port structure and whatever private data the
    user desires.  */
@@ -423,5 +436,6 @@ extern int _ports_flags;
 void _ports_complete_deallocate (struct port_info *);
 error_t _ports_create_port_internal (struct port_class *, struct port_bucket *,
                                     size_t, void *, int);
+error_t _ports_trace_message (mach_port_t, const mach_msg_header_t *);
 
 #endif
diff --git a/tmpfs/Makefile b/tmpfs/Makefile
index fdcae34..fc27909 100644
--- a/tmpfs/Makefile
+++ b/tmpfs/Makefile
@@ -23,7 +23,8 @@ target = tmpfs
 SRCS = tmpfs.c node.c dir.c pager-stubs.c
 OBJS = $(SRCS:.c=.o) default_pagerUser.o
 # XXX The shared libdiskfs requires libstore even though we don't use it here.
-HURDLIBS = diskfs pager iohelp fshelp store ports ihash shouldbeinlibc
+HURDLIBS = diskfs pager iohelp fshelp store ports ihash introspection \
+       shouldbeinlibc
 OTHERLIBS = -lpthread
 
 include ../Makeconf
-- 
2.1.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]