Fix the handle locking in stdio

Fix the handle locking in stdio to use flockfile/funlockfile
internally when and where required.  Macros in <stdio.h> are updated
to automatically call the underlying functions when the process is
threaded to obtain the necessary locking.  A private mutex is added
to protect __sglue, the internal list of FILE handles, and another
to protect the one-time initialization.  Some routines in libc that
use getc() change to use getc_unlocked() as they're either protected
by their own lock or aren't thread-safe routines anyway.

Based on OpenBSD change by guenther@openbsd.org
http://www.mail-archive.com/source-changes@cvs.openbsd.org/msg01015.html

Bug: 3446659
Change-Id: Ie82116e358c541718d6709ec45ca6796be5a007b
diff --git a/libc/stdio/fread.c b/libc/stdio/fread.c
index 69c40b3..649db17 100644
--- a/libc/stdio/fread.c
+++ b/libc/stdio/fread.c
@@ -39,9 +39,8 @@
 static int
 lflush(FILE *fp)
 {
-
     if ((fp->_flags & (__SLBF|__SWR)) == (__SLBF|__SWR))
-        return (__sflush(fp));
+        return (__sflush_locked(fp));
     return (0);
 }
 
@@ -60,6 +59,7 @@
      */
     if ((resid = count * size) == 0)
         return (0);
+    FLOCKFILE(fp);
     if (fp->_r < 0)
         fp->_r = 0;
     total = resid;
@@ -79,20 +79,25 @@
         fp->_r = 0;     /* largely a convenience for callers */
 
         /* SysV does not make this test; take it out for compatibility */
-        if (fp->_flags & __SEOF)
+        if (fp->_flags & __SEOF) {
+            FUNLOCKFILE(fp);
             return (EOF);
+        }
 
         /* if not already reading, have to be reading and writing */
         if ((fp->_flags & __SRD) == 0) {
             if ((fp->_flags & __SRW) == 0) {
-                errno = EBADF;
                 fp->_flags |= __SERR;
+                FUNLOCKFILE(fp);
+                errno = EBADF;
                 return (EOF);
             }
             /* switch to reading */
             if (fp->_flags & __SWR) {
-                if (__sflush(fp))
+                if (__sflush(fp)) {
+                    FUNLOCKFILE(fp);
                     return (EOF);
+                }
                 fp->_flags &= ~__SWR;
                 fp->_w = 0;
                 fp->_lbfsize = 0;
@@ -116,8 +121,16 @@
          * standard.
          */
 
-        if (fp->_flags & (__SLBF|__SNBF))
+        if (fp->_flags & (__SLBF|__SNBF)) {
+            /* Ignore this file in _fwalk to deadlock. */
+            fp->_flags |= __SIGN;
             (void) _fwalk(lflush);
+            fp->_flags &= ~__SIGN;
+
+            /* Now flush this file without locking it. */
+            if ((fp->_flags & (__SLBF|__SWR)) == (__SLBF|__SWR))
+                __sflush(fp);
+        }
 
         while (resid > 0) {
             int   len = (*fp->_read)(fp->_cookie, p, resid );
@@ -128,11 +141,13 @@
                 else {
                     fp->_flags |= __SERR;
                 }
+                FUNLOCKFILE(fp);
                 return ((total - resid) / size);
             }
             p     += len;
             resid -= len;
         }
+        FUNLOCKFILE(fp);
         return (count);
     }
     else
@@ -146,6 +161,7 @@
             resid -= r;
             if (__srefill(fp)) {
                 /* no more input: return partial result */
+                FUNLOCKFILE(fp);
                 return ((total - resid) / size);
             }
         }
@@ -154,5 +170,6 @@
     (void)memcpy((void *)p, (void *)fp->_p, resid);
     fp->_r -= resid;
     fp->_p += resid;
+    FUNLOCKFILE(fp);
     return (count);
 }