From 3cd552c422a2bed42e5c23c997e0e5039c8f8fbc Mon Sep 17 00:00:00 2001
From: Justus Winter <4winter@informatik.uni-hamburg.de>
Date: Wed, 21 May 2014 16:47:14 +0200
Subject: [PATCH hurd 3/9] libports: implement the Hurd server introspection
protocol
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 | 194 ++++++++++++++++++++++++++++++++++++++++++
libports/manage-multithread.c | 12 +++
libports/manage-one-thread.c | 13 +++
libports/ports.h | 15 ++++
tmpfs/Makefile | 3 +-
11 files changed, 268 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 af881f8..ec98bad 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 extern-inline.c port-deref-deferred.c
+ interrupted.c extern-inline.c port-deref-deferred.c introspection.c
installhdrs = ports.h port-deref-deferred.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 82c00a4..34559f5 100644
--- a/libports/create-bucket.c
+++ b/libports/create-bucket.c
@@ -49,5 +49,12 @@ ports_create_bucket ()
hurd_ihash_init (&ret->htable, offsetof (struct port_info, hentry));
ret->rpcs = ret->flags = ret->count = 0;
_ports_threadpool_init (&ret->threadpool);
+ 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..07f8624
--- /dev/null
+++ b/libports/introspection.c
@@ -0,0 +1,194 @@
+/* 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 . */
+
+#include
+#include
+#include
+#include
+#include
+
+#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 if it is not already running. */
+void
+_ports_start_introspection_server (void)
+{
+ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+ static int initialized = 0;
+ error_t err;
+ pthread_t thread;
+
+ pthread_mutex_lock (&lock);
+ if (! initialized)
+ {
+ err = pthread_create (&thread, NULL,
+ service_introspection_requests, NULL);
+ if (err)
+ error (0, err, "Error starting introspection server");
+ else
+ {
+ pthread_detach (thread);
+ initialized = 1;
+ }
+ }
+ pthread_mutex_unlock (&lock);
+}
+
+/* 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 /* XXX */] = 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;
+ ports_port_deref (pi);
+ return 0;
+}
diff --git a/libports/manage-multithread.c b/libports/manage-multithread.c
index 60743d9..d2e7dbe 100644
--- a/libports/manage-multithread.c
+++ b/libports/manage-multithread.c
@@ -21,6 +21,7 @@
#include "ports.h"
#include
#include
+#include
#include
#include
#include
@@ -189,6 +190,11 @@ ports_manage_port_operations_multithread (struct port_bucket *bucket,
if (pi)
{
+ mach_port_t trace_port = pi->class->trace_port;
+ mach_port_t trace_id;
+ if (__builtin_expect (MACH_PORT_VALID (trace_port), 0))
+ introspection_trace_request (trace_port, inp, &trace_id);
+
error_t err = ports_begin_rpc (pi, inp->msgh_id, &link);
if (err)
{
@@ -207,6 +213,9 @@ 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))
+ introspection_trace_message (trace_port, outp, trace_id);
}
else
{
@@ -281,5 +290,8 @@ ports_manage_port_operations_multithread (struct port_bucket *bucket,
master thread from going away. */
global_timeout = 0;
+ /* Make sure the introspection server is running. */
+ _ports_start_introspection_server ();
+
thread_function ((void *) 1);
}
diff --git a/libports/manage-one-thread.c b/libports/manage-one-thread.c
index b920338..86d575e 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
+
#include "ports.h"
void
@@ -80,6 +82,11 @@ ports_manage_port_operations_one_thread (struct port_bucket *bucket,
if (pi)
{
+ mach_port_t trace_port = pi->class->trace_port;
+ mach_port_t trace_id;
+ if (__builtin_expect (MACH_PORT_VALID (trace_port), 0))
+ introspection_trace_request (trace_port, inp, &trace_id);
+
err = ports_begin_rpc (pi, inp->msgh_id, &link);
if (err)
{
@@ -96,6 +103,9 @@ 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))
+ introspection_trace_message (trace_port, outp, trace_id);
}
else
{
@@ -114,6 +124,9 @@ ports_manage_port_operations_one_thread (struct port_bucket *bucket,
zero. */
timeout = 0;
+ /* Make sure the introspection server is running. */
+ _ports_start_introspection_server ();
+
_ports_thread_online (&bucket->threadpool, &thread);
do
err = mach_msg_server_timeout (internal_demuxer, 0, bucket->portset,
diff --git a/libports/ports.h b/libports/ports.h
index 9299bc4..e61b38c 100644
--- a/libports/ports.h
+++ b/libports/ports.h
@@ -76,6 +76,7 @@ struct port_bucket
int flags;
int count;
struct ports_threadpool threadpool;
+ const char *label;
};
/* FLAGS above are the following: */
#define PORT_BUCKET_INHIBITED PORTS_INHIBITED
@@ -91,7 +92,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
@@ -160,6 +164,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
@@ -169,6 +176,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. */
@@ -482,5 +495,7 @@ 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 *);
+void _ports_start_introspection_server (void);
#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.4