Userspace handling of errstr and errno (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Sun, 4 Aug 2013 02:48:46 +0000 (19:48 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Sun, 4 Aug 2013 02:48:46 +0000 (19:48 -0700)
Since not all uthreads have TLS, errno and the new errstr need to be
decoupled from the TLS.

When we're a uthread, we'll use storage in the uthread struct for errno
and errstr.  Otherwise, we'll default to the TLS locations (for vcores).
ld.so will continue to use its own area.  Very early in start.c, before
we call out to uthread code, we'd also use the TLS location.

perror() will print out the errstr, if there is one like so:

"your-message: errno-translated-to-text, errstr"

Rebuild your cross compiler.

tools/compilers/gcc-glibc/glibc-2.14.1-ros/include/errno.h [new file with mode: 0644]
tools/compilers/gcc-glibc/glibc-2.14.1-ros/sysdeps/ros/Versions
tools/compilers/gcc-glibc/glibc-2.14.1-ros/sysdeps/ros/bits/errno.h
tools/compilers/gcc-glibc/glibc-2.14.1-ros/sysdeps/ros/errno.c
tools/compilers/gcc-glibc/glibc-2.14.1-ros/sysdeps/ros/perror.c [new file with mode: 0644]
tools/compilers/gcc-glibc/glibc-2.14.1-ros/sysdeps/ros/syscall.c
user/parlib/include/uthread.h
user/parlib/uthread.c

diff --git a/tools/compilers/gcc-glibc/glibc-2.14.1-ros/include/errno.h b/tools/compilers/gcc-glibc/glibc-2.14.1-ros/include/errno.h
new file mode 100644 (file)
index 0000000..b46d0b3
--- /dev/null
@@ -0,0 +1,54 @@
+/* Modified for Akaros, removed the redefinition of errno */
+
+#ifndef _ERRNO_H
+
+#include <stdlib/errno.h>
+
+#if defined _ERRNO_H && !defined _ISOMAC && !defined __cplusplus
+
+# ifdef IS_IN_rtld
+#  include <dl-sysdep.h>
+# endif
+
+# if RTLD_PRIVATE_ERRNO
+/* The dynamic linker uses its own private errno variable.
+   All access to errno inside the dynamic linker is serialized,
+   so a single (hidden) global variable is all it needs.  */
+
+#  undef  errno
+#  define errno rtld_errno
+extern int rtld_errno attribute_hidden;
+
+# else
+
+#  include <tls.h>
+
+/* ROS doesn't want the redef of errno */
+#  ifndef __ros__
+#   if USE___THREAD
+#    undef  errno
+#    ifndef NOT_IN_libc
+#     define errno __libc_errno
+#    else
+#     define errno errno               /* For #ifndef errno tests.  */
+#    endif
+extern __thread int errno attribute_tls_model_ie;
+#   endif
+#  endif
+
+# endif        /* RTLD_PRIVATE_ERRNO */
+
+# define __set_errno(val) (errno = (val))
+
+# ifndef __ASSEMBLER__
+extern int *__errno_location (void) __THROW __attribute__ ((__const__))
+#  if RTLD_PRIVATE_ERRNO
+     attribute_hidden
+#  endif
+;
+libc_hidden_proto (__errno_location)
+# endif
+
+#endif /* _ERRNO_H */
+
+#endif /* ! _ERRNO_H */
index dea6ad4..d11ba82 100644 (file)
@@ -1,6 +1,11 @@
 libc {
   GLIBC_2.0 {
+    __errno_location_tls;
+    __errstr_location_tls;
+    ros_errno_loc;
+    ros_errstr_loc;
     __errno_location;
+    errstr;
     ros_syscall_blockon;
     ros_syscall_sync;
     __ros_scp_syscall_blockon;
index 0a31f39..7b61c73 100644 (file)
@@ -2,8 +2,21 @@
 #define _BITS_ERRNO_H
 
 #ifndef __ASSEMBLER__
-  extern int* __errno_location(void);
-  #define errno (*__errno_location())
+
+int *__errno_location_tls(void);
+char *__errstr_location_tls(void);
+extern int *(*ros_errno_loc)(void);
+extern char *(*ros_errstr_loc)(void);
+int *__errno_location(void);
+#define errno (*__errno_location())
+char *errstr(void);    /* can't macro, errstr is used internally in libc */
+
+# ifdef libc_hidden_proto
+libc_hidden_proto(__errno_location_tls)
+libc_hidden_proto(__errstr_location_tls)
+libc_hidden_proto(errstr)
+# endif
+
 #endif
 
 #include <ros/errno.h>
index 508d607..3004bc0 100644 (file)
 /* Code compiled for rtld has errno #defined to rtld_errno. */
 int rtld_errno attribute_hidden;
 #define errno rtld_errno
+char __errstr_tls[MAX_ERRSTR_LEN] = {0};
 
 #else
 
 __thread int errno;
 extern __thread int __libc_errno __attribute__ ((alias ("errno")))
   attribute_hidden;
+__thread char __errstr_tls[MAX_ERRSTR_LEN] = {0};
 
 #endif
 
-int* __errno_location(void)
+/* this is the glibc default, exported so uthread.c can use them */
+int *__errno_location_tls(void)
 {
-  return &errno;
+       return &errno;
 }
+
+char *__errstr_location_tls(void)
+{
+       return __errstr_tls;
+}
+
+/* These func ptrs will be used to access errno_loc and errstr_loc.  can be
+ * overriden at runtime (uthread code will do this) */
+int *(*ros_errno_loc)(void) = __errno_location_tls;
+char *(*ros_errstr_loc)(void) = __errstr_location_tls;
+
+/* errno calls this (and derefs the result).  it's also called internally */
+int *__errno_location(void)
+{
+       return ros_errno_loc();
+}
+
+/* libc doesn't really know about errstr, but we'll use it in syscall.c */
+char *errstr(void)
+{
+       return ros_errstr_loc();
+}
+
+/* Don't try to hidden_data_def the function pointers.  Won't allow us to
+ * switch, or otherwise track the right location. */
+libc_hidden_def(__errno_location_tls)
+libc_hidden_def(__errstr_location_tls)
 libc_hidden_def(__errno_location)
+libc_hidden_def(errstr)
diff --git a/tools/compilers/gcc-glibc/glibc-2.14.1-ros/sysdeps/ros/perror.c b/tools/compilers/gcc-glibc/glibc-2.14.1-ros/sysdeps/ros/perror.c
new file mode 100644 (file)
index 0000000..d173672
--- /dev/null
@@ -0,0 +1,94 @@
+/* Copyright (C) 1991-1993,1997,1998,2000-2005,2011
+   Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C 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.1 of the License, or (at your option) any later version.
+
+   The GNU C 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 the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Modified for Akaros to print errstr() */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include "libioP.h"
+
+static void
+perror_internal (FILE *fp, const char *s, int errnum)
+{
+  char buf[1024];
+  const char *colon, *comma;
+  const char *errstring;
+  char *ros_errstr = errstr();
+
+  if (s == NULL || *s == '\0')
+    s = colon = "";
+  else
+    colon = ": ";
+
+  /* ros_errstr should never be 0, but just in case. */
+  if (ros_errstr == NULL || *ros_errstr == '\0')
+    ros_errstr = comma = "";
+  else
+    comma = ", ";
+
+  errstring = __strerror_r (errnum, buf, sizeof buf);
+
+  (void) __fxprintf(fp, "%s%s%s%s%s\n", s, colon, errstring, comma, ros_errstr);
+}
+
+
+/* Print a line on stderr consisting of the text in S, a colon, a space,
+   a message describing the meaning of the contents of `errno' and a newline.
+   If S is NULL or "", the colon and space are omitted.  */
+void
+perror (const char *s)
+{
+  int errnum = errno;
+  FILE *fp;
+  int fd = -1;
+
+
+  /* The standard says that 'perror' must not change the orientation
+     of the stream.  What is supposed to happen when the stream isn't
+     oriented yet?  In this case we'll create a new stream which is
+     using the same underlying file descriptor.  */
+  if (__builtin_expect (_IO_fwide (stderr, 0) != 0, 1)
+      || (fd = fileno (stderr)) == -1
+      || (fd = __dup (fd)) == -1
+      || (fp = fdopen (fd, "w+")) == NULL)
+    {
+      if (__builtin_expect (fd != -1, 0))
+       __close (fd);
+
+      /* Use standard error as is.  */
+      perror_internal (stderr, s, errnum);
+    }
+  else
+    {
+      /* We don't have to do any special hacks regarding the file
+        position.  Since the stderr stream wasn't used so far we just
+        write to the descriptor.  */
+      perror_internal (fp, s, errnum);
+
+      if (_IO_ferror_unlocked (fp))
+       stderr->_flags |= _IO_ERR_SEEN;
+
+      /* Close the stream.  */
+      fclose (fp);
+    }
+}
+libc_hidden_def (perror)
index e127228..3ae0c05 100644 (file)
@@ -143,8 +143,10 @@ long __ros_syscall_errno(unsigned int _num, long _a0, long _a1, long _a2,
 {
        struct syscall sysc = __ros_syscall_inline(_num, _a0, _a1, _a2, _a3,
                                                   _a4, _a5);
-       if (__builtin_expect(sysc.err, 0))
+       if (__builtin_expect(sysc.err, 0)) {
                errno = sysc.err;
+               memcpy(errstr(), sysc.errstr, MAX_ERRSTR_LEN);
+       }
        return sysc.retval;
 }
 libc_hidden_def(__ros_syscall_errno)
index 448f496..4a1d2cd 100644 (file)
@@ -28,6 +28,8 @@ struct uthread {
        int state;
        void (*yield_func)(struct uthread*, void*);
        void *yield_arg;
+       int err_no;
+       char err_str[MAX_ERRSTR_LEN];
 };
 typedef struct uthread uthread_t;
 extern __thread struct uthread *current_uthread;
index 51f001c..a0945d0 100644 (file)
@@ -113,6 +113,25 @@ static void scp_vcctx_ready(void)
                             old_flags & ~VC_SCP_NOVCCTX));
 }
 
+/* For both of these, VC ctx uses the usual TLS errno/errstr.  Uthreads use
+ * their own storage.  Since we're called after manage_thread0, we should always
+ * have current_uthread if we are not in vc ctx. */
+static int *__ros_errno_loc(void)
+{
+       if (in_vcore_context())
+               return __errno_location_tls();
+       else
+               return &current_uthread->err_no;
+}
+
+static char *__ros_errstr_loc(void)
+{
+       if (in_vcore_context())
+               return __errstr_location_tls();
+       else
+               return current_uthread->err_str;
+}
+
 /* Slim-init - sets up basic uthreading for when we are in _S mode and before
  * we set up the 2LS.  Some apps may not have a 2LS and thus never do the full
  * vcore/2LS/uthread init. */
@@ -133,6 +152,10 @@ void uthread_slim_init(void)
         * before blocking while an _M.  it's harmless (and probably saner) to do it
         * earlier, so we do it as early as possible. */
        ros_syscall_blockon = __ros_mcp_syscall_blockon;
+       /* Switch our errno/errstr functions to be uthread-aware.  See glibc's
+        * errno.c for more info. */
+       ros_errno_loc = __ros_errno_loc;
+       ros_errstr_loc = __ros_errstr_loc;
 }
 
 /* 2LSs shouldn't call uthread_vcore_entry directly */