Patchwork libgo patch committed: Clean up directory reading code

login
register
mail settings
Submitter Ian Taylor
Date Dec. 6, 2012, 2 a.m.
Message ID <mcrvccgq6rv.fsf@google.com>
Download mbox | patch
Permalink /patch/204094/
State New
Headers show

Comments

Ian Taylor - Dec. 6, 2012, 2 a.m.
This patch to libgo cleans up the directory reading code.  It now calls
Entersyscall and Exitsyscall around calls to pathconf and closedir,
which are necessary when using a fused file system.  It avoids a minor
race condition calling pathconf.  It generally neatens the code.
Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
Committed to mainline.

Ian

Patch

diff -r a35a8711bc0a libgo/go/os/dir.go
--- a/libgo/go/os/dir.go	Wed Dec 05 00:46:54 2012 -0800
+++ b/libgo/go/os/dir.go	Wed Dec 05 17:21:15 2012 -0800
@@ -6,6 +6,7 @@ 
 
 import (
 	"io"
+	"sync/atomic"
 	"syscall"
 	"unsafe"
 )
@@ -29,27 +30,42 @@ 
 	return len(n)
 }
 
-var elen int
+var nameMax int32
 
 func (file *File) readdirnames(n int) (names []string, err error) {
-	if elen == 0 {
-		var dummy syscall.Dirent
-		elen = (int(unsafe.Offsetof(dummy.Name)) +
-			libc_pathconf(syscall.StringBytePtr(file.name), syscall.PC_NAME_MAX) +
-			1)
-	}
+	if file.dirinfo == nil {
+		p, err := syscall.BytePtrFromString(file.name)
+		if err != nil {
+			return nil, err
+		}
 
-	if file.dirinfo == nil {
+		elen := int(atomic.LoadInt32(&nameMax))
+		if elen == 0 {
+			syscall.Entersyscall()
+			plen := libc_pathconf(p, syscall.PC_NAME_MAX)
+			syscall.Exitsyscall()
+			if plen < 1024 {
+				plen = 1024
+			}
+			var dummy syscall.Dirent
+			elen = int(unsafe.Offsetof(dummy.Name)) + plen + 1
+			atomic.StoreInt32(&nameMax, int32(elen))
+		}
+
+		syscall.Entersyscall()
+		r := libc_opendir(p)
+		errno := syscall.GetErrno()
+		syscall.Exitsyscall()
+		if r == nil {
+			return nil, &PathError{"opendir", file.name, errno}
+		}
+
 		file.dirinfo = new(dirInfo)
 		file.dirinfo.buf = make([]byte, elen)
-		p := syscall.StringBytePtr(file.name)
-		syscall.Entersyscall()
-		r := libc_opendir(p)
-		syscall.Exitsyscall()
 		file.dirinfo.dir = r
 	}
 
-	entry_dirent := (*syscall.Dirent)(unsafe.Pointer(&file.dirinfo.buf[0]))
+	entryDirent := (*syscall.Dirent)(unsafe.Pointer(&file.dirinfo.buf[0]))
 
 	size := n
 	if size <= 0 {
@@ -59,24 +75,20 @@ 
 
 	names = make([]string, 0, size) // Empty with room to grow.
 
-	dir := file.dirinfo.dir
-	if dir == nil {
-		return names, NewSyscallError("opendir", syscall.GetErrno())
-	}
-
 	for n != 0 {
-		var result *syscall.Dirent
-		pr := &result
+		var dirent *syscall.Dirent
+		pr := &dirent
 		syscall.Entersyscall()
-		i := libc_readdir_r(dir, entry_dirent, pr)
+		i := libc_readdir_r(file.dirinfo.dir, entryDirent, pr)
 		syscall.Exitsyscall()
 		if i != 0 {
 			return names, NewSyscallError("readdir_r", i)
 		}
-		if result == nil {
+		if dirent == nil {
 			break // EOF
 		}
-		var name = string(result.Name[0:clen(result.Name[0:])])
+		bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
+		var name = string(bytes[0:clen(bytes[:])])
 		if name == "." || name == ".." { // Useless names
 			continue
 		}
diff -r a35a8711bc0a libgo/go/os/file_unix.go
--- a/libgo/go/os/file_unix.go	Wed Dec 05 00:46:54 2012 -0800
+++ b/libgo/go/os/file_unix.go	Wed Dec 05 17:21:15 2012 -0800
@@ -108,8 +108,13 @@ 
 	}
 
 	if file.dirinfo != nil {
-		if libc_closedir(file.dirinfo.dir) < 0 && err == nil {
-			err = &PathError{"closedir", file.name, syscall.GetErrno()}
+		syscall.Entersyscall()
+		i := libc_closedir(file.dirinfo.dir)
+		errno := syscall.GetErrno()
+		syscall.Exitsyscall()
+		file.dirinfo = nil
+		if i < 0 && err == nil {
+			err = &PathError{"closedir", file.name, errno}
 		}
 	}