Browse Source

Merge pull request #2998 from laytan/os-improvements

OS improvements
gingerBill 1 year ago
parent
commit
dd7c65a89c
5 changed files with 82 additions and 13 deletions
  1. 21 5
      core/os/os_darwin.odin
  2. 13 2
      core/os/os_freebsd.odin
  3. 22 4
      core/os/os_linux.odin
  4. 13 2
      core/os/os_openbsd.odin
  5. 13 0
      core/os/stream.odin

+ 21 - 5
core/os/os_darwin.odin

@@ -568,15 +568,24 @@ close :: proc(fd: Handle) -> bool {
 	return _unix_close(fd) == 0
 	return _unix_close(fd) == 0
 }
 }
 
 
+// If you read or write more than `SSIZE_MAX` bytes, most darwin implementations will return `EINVAL`
+// but it is really implementation defined. `SSIZE_MAX` is also implementation defined but usually
+// the max of an i32 on Darwin.
+// In practice a read/write call would probably never read/write these big buffers all at once,
+// which is why the number of bytes is returned and why there are procs that will call this in a
+// loop for you.
+// We set a max of 1GB to keep alignment and to be safe.
 @(private)
 @(private)
-MAX_RW :: 0x7fffffff // The limit on Darwin is max(i32), trying to read/write more than that fails.
+MAX_RW :: 1 << 30
 
 
 write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
 write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
 	if len(data) == 0 {
 	if len(data) == 0 {
 		return 0, ERROR_NONE
 		return 0, ERROR_NONE
 	}
 	}
 
 
-	bytes_written := _unix_write(fd, raw_data(data), c.size_t(len(data)))
+	to_write := min(c.size_t(len(data)), MAX_RW)
+
+	bytes_written := _unix_write(fd, raw_data(data), to_write)
 	if bytes_written < 0 {
 	if bytes_written < 0 {
 		return -1, Errno(get_last_error())
 		return -1, Errno(get_last_error())
 	}
 	}
@@ -588,18 +597,23 @@ read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
 		return 0, ERROR_NONE
 		return 0, ERROR_NONE
 	}
 	}
 
 
-	bytes_read := _unix_read(fd, raw_data(data), c.size_t(len(data)))
+	to_read := min(c.size_t(len(data)), MAX_RW)
+
+	bytes_read := _unix_read(fd, raw_data(data), to_read)
 	if bytes_read < 0 {
 	if bytes_read < 0 {
 		return -1, Errno(get_last_error())
 		return -1, Errno(get_last_error())
 	}
 	}
 	return bytes_read, ERROR_NONE
 	return bytes_read, ERROR_NONE
 }
 }
+
 read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
 read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
 	if len(data) == 0 {
 	if len(data) == 0 {
 		return 0, ERROR_NONE
 		return 0, ERROR_NONE
 	}
 	}
 
 
-	bytes_read := _unix_pread(fd, raw_data(data), c.size_t(len(data)), offset)
+	to_read := min(c.size_t(len(data)), MAX_RW)
+
+	bytes_read := _unix_pread(fd, raw_data(data), to_read, offset)
 	if bytes_read < 0 {
 	if bytes_read < 0 {
 		return -1, Errno(get_last_error())
 		return -1, Errno(get_last_error())
 	}
 	}
@@ -611,7 +625,9 @@ write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
 		return 0, ERROR_NONE
 		return 0, ERROR_NONE
 	}
 	}
 
 
-	bytes_written := _unix_pwrite(fd, raw_data(data), c.size_t(len(data)), offset)
+	to_write := min(c.size_t(len(data)), MAX_RW)
+
+	bytes_written := _unix_pwrite(fd, raw_data(data), to_write, offset)
 	if bytes_written < 0 {
 	if bytes_written < 0 {
 		return -1, Errno(get_last_error())
 		return -1, Errno(get_last_error())
 	}
 	}

+ 13 - 2
core/os/os_freebsd.odin

@@ -326,8 +326,17 @@ close :: proc(fd: Handle) -> Errno {
 	return ERROR_NONE
 	return ERROR_NONE
 }
 }
 
 
+// If you read or write more than `INT_MAX` bytes, FreeBSD returns `EINVAL`.
+// In practice a read/write call would probably never read/write these big buffers all at once,
+// which is why the number of bytes is returned and why there are procs that will call this in a
+// loop for you.
+// We set a max of 1GB to keep alignment and to be safe.
+@(private)
+MAX_RW :: 1 << 30
+
 read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
 read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
-	bytes_read := _unix_read(fd, &data[0], c.size_t(len(data)))
+	to_read    := min(c.size_t(len(data)), MAX_RW)
+	bytes_read := _unix_read(fd, &data[0], to_read)
 	if bytes_read == -1 {
 	if bytes_read == -1 {
 		return -1, Errno(get_last_error())
 		return -1, Errno(get_last_error())
 	}
 	}
@@ -338,7 +347,9 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
 	if len(data) == 0 {
 	if len(data) == 0 {
 		return 0, ERROR_NONE
 		return 0, ERROR_NONE
 	}
 	}
-	bytes_written := _unix_write(fd, &data[0], c.size_t(len(data)))
+
+	to_write      := min(c.size_t(len(data)), MAX_RW)
+	bytes_written := _unix_write(fd, &data[0], to_write)
 	if bytes_written == -1 {
 	if bytes_written == -1 {
 		return -1, Errno(get_last_error())
 		return -1, Errno(get_last_error())
 	}
 	}

+ 22 - 4
core/os/os_linux.odin

@@ -569,12 +569,23 @@ close :: proc(fd: Handle) -> Errno {
 	return _get_errno(unix.sys_close(int(fd)))
 	return _get_errno(unix.sys_close(int(fd)))
 }
 }
 
 
+// If you read or write more than `SSIZE_MAX` bytes, result is implementation defined (probably an error).
+// `SSIZE_MAX` is also implementation defined but usually the max of a `ssize_t` which is `max(int)` in Odin.
+// In practice a read/write call would probably never read/write these big buffers all at once,
+// which is why the number of bytes is returned and why there are procs that will call this in a
+// loop for you.
+// We set a max of 1GB to keep alignment and to be safe.
+@(private)
+MAX_RW :: 1 << 30
+
 read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
 read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
 	if len(data) == 0 {
 	if len(data) == 0 {
 		return 0, ERROR_NONE
 		return 0, ERROR_NONE
 	}
 	}
 
 
-	bytes_read := unix.sys_read(int(fd), raw_data(data), len(data))
+	to_read := min(uint(len(data)), MAX_RW)
+
+	bytes_read := unix.sys_read(int(fd), raw_data(data), to_read)
 	if bytes_read < 0 {
 	if bytes_read < 0 {
 		return -1, _get_errno(bytes_read)
 		return -1, _get_errno(bytes_read)
 	}
 	}
@@ -586,18 +597,23 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
 		return 0, ERROR_NONE
 		return 0, ERROR_NONE
 	}
 	}
 
 
-	bytes_written := unix.sys_write(int(fd), raw_data(data), len(data))
+	to_write := min(uint(len(data)), MAX_RW)
+
+	bytes_written := unix.sys_write(int(fd), raw_data(data), to_write)
 	if bytes_written < 0 {
 	if bytes_written < 0 {
 		return -1, _get_errno(bytes_written)
 		return -1, _get_errno(bytes_written)
 	}
 	}
 	return bytes_written, ERROR_NONE
 	return bytes_written, ERROR_NONE
 }
 }
+
 read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
 read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
 	if len(data) == 0 {
 	if len(data) == 0 {
 		return 0, ERROR_NONE
 		return 0, ERROR_NONE
 	}
 	}
 
 
-	bytes_read := unix.sys_pread(int(fd), raw_data(data), len(data), offset)
+	to_read := min(uint(len(data)), MAX_RW)
+
+	bytes_read := unix.sys_pread(int(fd), raw_data(data), to_read, offset)
 	if bytes_read < 0 {
 	if bytes_read < 0 {
 		return -1, _get_errno(bytes_read)
 		return -1, _get_errno(bytes_read)
 	}
 	}
@@ -609,7 +625,9 @@ write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
 		return 0, ERROR_NONE
 		return 0, ERROR_NONE
 	}
 	}
 
 
-	bytes_written := unix.sys_pwrite(int(fd), raw_data(data), uint(len(data)), offset)
+	to_write := min(uint(len(data)), MAX_RW)
+
+	bytes_written := unix.sys_pwrite(int(fd), raw_data(data), to_write, offset)
 	if bytes_written < 0 {
 	if bytes_written < 0 {
 		return -1, _get_errno(bytes_written)
 		return -1, _get_errno(bytes_written)
 	}
 	}

+ 13 - 2
core/os/os_openbsd.odin

@@ -325,8 +325,17 @@ close :: proc(fd: Handle) -> Errno {
 	return ERROR_NONE
 	return ERROR_NONE
 }
 }
 
 
+// If you read or write more than `SSIZE_MAX` bytes, OpenBSD returns `EINVAL`.
+// In practice a read/write call would probably never read/write these big buffers all at once,
+// which is why the number of bytes is returned and why there are procs that will call this in a
+// loop for you.
+// We set a max of 1GB to keep alignment and to be safe.
+@(private)
+MAX_RW :: 1 << 30
+
 read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
 read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
-	bytes_read := _unix_read(fd, &data[0], c.size_t(len(data)))
+	to_read    := min(c.size_t(len(data)), MAX_RW)
+	bytes_read := _unix_read(fd, &data[0], to_read)
 	if bytes_read == -1 {
 	if bytes_read == -1 {
 		return -1, Errno(get_last_error())
 		return -1, Errno(get_last_error())
 	}
 	}
@@ -337,7 +346,9 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
 	if len(data) == 0 {
 	if len(data) == 0 {
 		return 0, ERROR_NONE
 		return 0, ERROR_NONE
 	}
 	}
-	bytes_written := _unix_write(fd, &data[0], c.size_t(len(data)))
+
+	to_write      := min(c.size_t(len(data)), MAX_RW)
+	bytes_written := _unix_write(fd, &data[0], to_write)
 	if bytes_written == -1 {
 	if bytes_written == -1 {
 		return -1, Errno(get_last_error())
 		return -1, Errno(get_last_error())
 	}
 	}

+ 13 - 0
core/os/stream.odin

@@ -27,19 +27,31 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
 	case .Read:
 	case .Read:
 		n_int, os_err = read(fd, p)
 		n_int, os_err = read(fd, p)
 		n = i64(n_int)
 		n = i64(n_int)
+		if n == 0 && os_err == 0 {
+			err = .EOF
+		}
 
 
 	case .Read_At:
 	case .Read_At:
 		when !(ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD) {
 		when !(ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD) {
 			n_int, os_err = read_at(fd, p, offset)
 			n_int, os_err = read_at(fd, p, offset)
 			n = i64(n_int)
 			n = i64(n_int)
+			if n == 0 && os_err == 0 {
+				err = .EOF
+			}
 		}
 		}
 	case .Write:
 	case .Write:
 		n_int, os_err = write(fd, p)
 		n_int, os_err = write(fd, p)
 		n = i64(n_int)
 		n = i64(n_int)
+		if n == 0 && os_err == 0 {
+			err = .EOF
+		}
 	case .Write_At:
 	case .Write_At:
 		when !(ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD) {
 		when !(ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD) {
 			n_int, os_err = write_at(fd, p, offset)
 			n_int, os_err = write_at(fd, p, offset)
 			n = i64(n_int)
 			n = i64(n_int)
+			if n == 0 && os_err == 0 {
+				err = .EOF
+			}
 		}
 		}
 	case .Seek:
 	case .Seek:
 		n, os_err = seek(fd, offset, int(whence))
 		n, os_err = seek(fd, offset, int(whence))
@@ -54,6 +66,7 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
 			return io.query_utility({.Close, .Flush, .Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Query})
 			return io.query_utility({.Close, .Flush, .Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Query})
 		}
 		}
 	}
 	}
+
 	if err == nil && os_err != 0 {
 	if err == nil && os_err != 0 {
 		when ODIN_OS == .Windows {
 		when ODIN_OS == .Windows {
 			if os_err == ERROR_HANDLE_EOF {
 			if os_err == ERROR_HANDLE_EOF {