summaryrefslogtreecommitdiff
path: root/pr/src/md/os2
diff options
context:
space:
mode:
Diffstat (limited to 'pr/src/md/os2')
-rw-r--r--pr/src/md/os2/Makefile51
-rw-r--r--pr/src/md/os2/os2_errors.c1053
-rw-r--r--pr/src/md/os2/os2cv.c332
-rw-r--r--pr/src/md/os2/os2gc.c73
-rw-r--r--pr/src/md/os2/os2inrval.c81
-rw-r--r--pr/src/md/os2/os2io.c620
-rw-r--r--pr/src/md/os2/os2misc.c513
-rw-r--r--pr/src/md/os2/os2poll.c165
-rw-r--r--pr/src/md/os2/os2sem.c74
-rw-r--r--pr/src/md/os2/os2sock.c770
-rw-r--r--pr/src/md/os2/os2thred.c245
11 files changed, 3977 insertions, 0 deletions
diff --git a/pr/src/md/os2/Makefile b/pr/src/md/os2/Makefile
new file mode 100644
index 00000000..1b23db00
--- /dev/null
+++ b/pr/src/md/os2/Makefile
@@ -0,0 +1,51 @@
+#
+# The contents of this file are subject to the Netscape Public License
+# Version 1.0 (the "NPL"); you may not use this file except in
+# compliance with the NPL. You may obtain a copy of the NPL at
+# http://www.mozilla.org/NPL/
+#
+# Software distributed under the NPL is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+# for the specific language governing rights and limitations under the
+# NPL.
+#
+# The Initial Developer of this code under the NPL is Netscape
+# Communications Corporation. Portions created by Netscape are
+# Copyright (C) 1998 Netscape Communications Corporation. All Rights
+# Reserved.
+#
+
+#! gmake
+
+MOD_DEPTH = ../../../..
+
+include $(MOD_DEPTH)/config/config.mk
+
+ifeq ($(OS_TARGET), OS2)
+CSRCS = \
+ os2misc.c \
+ os2sem.c \
+ os2inrval.c \
+ os2gc.c \
+ os2thred.c \
+ os2io.c \
+ os2cv.c \
+ os2sock.c \
+ os2_errors.c \
+ os2poll.c \
+ $(NULL)
+endif
+
+TARGETS = $(OBJS)
+
+INCLUDES = -I$(DIST)/include/private -I$(DIST)/include
+
+include $(MOD_DEPTH)/config/rules.mk
+
+export:: $(TARGETS)
+ @cmd /C "copy *.obj $(OBJDIR)\*.o > nul"
+
+install:: export
+
+
+
diff --git a/pr/src/md/os2/os2_errors.c b/pr/src/md/os2/os2_errors.c
new file mode 100644
index 00000000..33f1a062
--- /dev/null
+++ b/pr/src/md/os2/os2_errors.c
@@ -0,0 +1,1053 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+#include "prerror.h"
+#include "primpl.h"
+
+void _MD_os2_map_opendir_error(PRInt32 err)
+{
+ switch (err) {
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ PR_SetError(PR_FILE_NOT_FOUND_ERROR, err);
+ break;
+ case ERROR_ACCESS_DENIED:
+ PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err);
+ break;
+ case ERROR_INVALID_ADDRESS:
+ case ERROR_INVALID_ACCESS:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case ERROR_INVALID_NAME:
+ case ERROR_INVALID_PARAMETER:
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, err);
+ break;
+ case ERROR_TOO_MANY_OPEN_FILES:
+ case ERROR_NOT_DOS_DISK:
+ case ERROR_NOT_READY:
+ case ERROR_OPEN_FAILED:
+ case ERROR_PATH_BUSY:
+ case ERROR_CANNOT_MAKE:
+ PR_SetError(PR_IO_ERROR, err);
+ break;
+ case ERROR_DRIVE_LOCKED:
+ case ERROR_DEVICE_IN_USE:
+ PR_SetError(PR_FILE_IS_LOCKED_ERROR, err);
+ break;
+ case ERROR_FILENAME_EXCED_RANGE:
+ PR_SetError(PR_NAME_TOO_LONG_ERROR, err);
+ break;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_SHARING_BUFFER_EXCEEDED:
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_closedir_error(PRInt32 err)
+{
+ switch (err) {
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_ACCESS_DENIED:
+ case ERROR_INVALID_HANDLE:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_unix_readdir_error(PRInt32 err)
+{
+
+ switch (err) {
+ case ERROR_NO_MORE_FILES:
+ PR_SetError(PR_NO_MORE_FILES_ERROR, err);
+ break;
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_INVALID_HANDLE:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ERROR_INVALID_ADDRESS:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case ERROR_NOT_DOS_DISK:
+ case ERROR_LOCK_VIOLATION:
+ case ERROR_BROKEN_PIPE:
+ case ERROR_NOT_READY:
+ PR_SetError(PR_IO_ERROR, err);
+ break;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_MORE_DATA:
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_delete_error(PRInt32 err)
+{
+ switch (err) {
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ PR_SetError(PR_FILE_NOT_FOUND_ERROR, err);
+ break;
+ case ERROR_ACCESS_DENIED:
+ case ERROR_WRITE_PROTECT:
+ PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err);
+ break;
+ case ERROR_INVALID_ADDRESS:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case ERROR_DRIVE_LOCKED:
+ case ERROR_LOCKED:
+ case ERROR_SHARING_VIOLATION:
+ PR_SetError(PR_FILE_IS_LOCKED_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+/* The error code for stat() is in errno. */
+void _MD_os2_map_stat_error(PRInt32 err)
+{
+ switch (err) {
+ case ENOENT:
+ PR_SetError(PR_FILE_NOT_FOUND_ERROR, err);
+ break;
+ case EACCES:
+ PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ }
+}
+
+void _MD_os2_map_fstat_error(PRInt32 err)
+{
+ switch (err) {
+ case ERROR_ACCESS_DENIED:
+ PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err);
+ break;
+ case ERROR_INVALID_HANDLE:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ERROR_INVALID_ADDRESS:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case ERROR_NOT_READY:
+ case ERROR_PATH_BUSY:
+ PR_SetError(PR_IO_ERROR, err);
+ break;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_MORE_DATA:
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
+ break;
+ case ERROR_DRIVE_LOCKED:
+ case ERROR_LOCKED:
+ PR_SetError(PR_FILE_IS_LOCKED_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_rename_error(PRInt32 err)
+{
+ switch (err) {
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ PR_SetError(PR_FILE_NOT_FOUND_ERROR, err);
+ break;
+ case ERROR_ACCESS_DENIED:
+ PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err);
+ break;
+ case ERROR_INVALID_ADDRESS:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case ERROR_INVALID_NAME:
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, err);
+ break;
+ case ERROR_NOT_READY:
+ case ERROR_PATH_BUSY:
+ PR_SetError(PR_IO_ERROR, err);
+ break;
+ case ERROR_DRIVE_LOCKED:
+ PR_SetError(PR_FILE_IS_LOCKED_ERROR, err);
+ break;
+ case ERROR_FILENAME_EXCED_RANGE:
+ PR_SetError(PR_NAME_TOO_LONG_ERROR, err);
+ break;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_MORE_DATA:
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
+ break;
+ case ERROR_ALREADY_EXISTS:
+ case ERROR_FILE_EXISTS:
+ PR_SetError(PR_FILE_EXISTS_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+/* The error code for access() is in errno. */
+void _MD_os2_map_access_error(PRInt32 err)
+{
+ switch (err) {
+ case ENOENT:
+ PR_SetError(PR_FILE_NOT_FOUND_ERROR, err);
+ break;
+ case EACCES:
+ PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ }
+}
+
+void _MD_os2_map_mkdir_error(PRInt32 err)
+{
+ switch (err) {
+ case ERROR_ALREADY_EXISTS:
+ case ERROR_FILE_EXISTS:
+ PR_SetError(PR_FILE_EXISTS_ERROR, err);
+ break;
+ case ERROR_FILE_NOT_FOUND:
+ PR_SetError(PR_FILE_NOT_FOUND_ERROR, err);
+ break;
+ case ERROR_ACCESS_DENIED:
+ PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err);
+ break;
+ case ERROR_INVALID_ADDRESS:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case ERROR_INVALID_NAME:
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, err);
+ break;
+ case ERROR_NOT_READY:
+ case ERROR_PATH_BUSY:
+ PR_SetError(PR_IO_ERROR, err);
+ break;
+ case ERROR_DRIVE_LOCKED:
+ PR_SetError(PR_FILE_IS_LOCKED_ERROR, err);
+ break;
+ case ERROR_FILENAME_EXCED_RANGE:
+ PR_SetError(PR_NAME_TOO_LONG_ERROR, err);
+ break;
+ case ERROR_TOO_MANY_OPEN_FILES:
+ PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err);
+ break;
+ case ERROR_PATH_NOT_FOUND:
+ PR_SetError(PR_FILE_NOT_FOUND_ERROR, err);
+ break;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_MORE_DATA:
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
+ break;
+ case ERROR_DISK_FULL:
+ case ERROR_HANDLE_DISK_FULL:
+ PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err);
+ break;
+ case ERROR_WRITE_PROTECT:
+ PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_rmdir_error(PRInt32 err)
+{
+
+ switch (err) {
+ case ERROR_FILE_NOT_FOUND:
+ PR_SetError(PR_FILE_NOT_FOUND_ERROR, err);
+ break;
+ case ERROR_ACCESS_DENIED:
+ PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err);
+ break;
+ case ERROR_INVALID_ADDRESS:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case ERROR_INVALID_NAME:
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, err);
+ break;
+ case ERROR_NOT_READY:
+ case ERROR_PATH_BUSY:
+ PR_SetError(PR_IO_ERROR, err);
+ break;
+ case ERROR_DRIVE_LOCKED:
+ PR_SetError(PR_FILE_IS_LOCKED_ERROR, err);
+ break;
+ case ERROR_FILENAME_EXCED_RANGE:
+ PR_SetError(PR_NAME_TOO_LONG_ERROR, err);
+ break;
+ case ERROR_TOO_MANY_OPEN_FILES:
+ PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err);
+ break;
+ case ERROR_PATH_NOT_FOUND:
+ PR_SetError(PR_FILE_NOT_FOUND_ERROR, err);
+ break;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_MORE_DATA:
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
+ break;
+ case ERROR_WRITE_PROTECT:
+ PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_read_error(PRInt32 err)
+{
+ switch (err) {
+ case ERROR_ACCESS_DENIED:
+ PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err);
+ break;
+ case ERROR_INVALID_HANDLE:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ERROR_INVALID_ADDRESS:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case ERROR_NOT_READY:
+ case ERROR_PATH_BUSY:
+ PR_SetError(PR_IO_ERROR, err);
+ break;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_MORE_DATA:
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
+ break;
+ case ERROR_DRIVE_LOCKED:
+ case ERROR_LOCKED:
+ case ERROR_SHARING_VIOLATION:
+ PR_SetError(PR_FILE_IS_LOCKED_ERROR, err);
+ break;
+ case ERROR_NETNAME_DELETED:
+ PR_SetError(PR_CONNECT_RESET_ERROR, err);
+ break;
+ case EBADF:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ENOTSOCK:
+ PR_SetError(PR_NOT_SOCKET_ERROR, err);
+ break;
+ case SOCEFAULT:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_transmitfile_error(PRInt32 err)
+{
+ switch (err) {
+ case ERROR_ACCESS_DENIED:
+ PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err);
+ break;
+ case ERROR_INVALID_HANDLE:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ERROR_INVALID_ADDRESS:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case ERROR_NOT_READY:
+ case ERROR_PATH_BUSY:
+ PR_SetError(PR_IO_ERROR, err);
+ break;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_MORE_DATA:
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
+ break;
+ case ERROR_DRIVE_LOCKED:
+ case ERROR_LOCKED:
+ case ERROR_SHARING_VIOLATION:
+ PR_SetError(PR_FILE_IS_LOCKED_ERROR, err);
+ break;
+ case ERROR_FILENAME_EXCED_RANGE:
+ PR_SetError(PR_NAME_TOO_LONG_ERROR, err);
+ break;
+ case ERROR_TOO_MANY_OPEN_FILES:
+ PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err);
+ break;
+ case ERROR_PATH_NOT_FOUND:
+ PR_SetError(PR_FILE_NOT_FOUND_ERROR, err);
+ break;
+ case EBADF:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ENOTSOCK:
+ PR_SetError(PR_NOT_SOCKET_ERROR, err);
+ break;
+ case SOCEFAULT:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_write_error(PRInt32 err)
+{
+ switch (err) {
+ case ERROR_ACCESS_DENIED:
+ case ERROR_WRITE_PROTECT:
+ PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err);
+ break;
+ case ERROR_INVALID_HANDLE:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ERROR_INVALID_ADDRESS:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case ERROR_NOT_READY:
+ case ERROR_PATH_BUSY:
+ PR_SetError(PR_IO_ERROR, err);
+ break;
+ case ERROR_DRIVE_LOCKED:
+ case ERROR_LOCKED:
+ case ERROR_SHARING_VIOLATION:
+ PR_SetError(PR_FILE_IS_LOCKED_ERROR, err);
+ break;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_MORE_DATA:
+ case ERROR_DISK_FULL:
+ case ERROR_HANDLE_DISK_FULL:
+ case ENOSPC:
+ PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err);
+ break;
+ case ERROR_NETNAME_DELETED:
+ PR_SetError(PR_CONNECT_RESET_ERROR, err);
+ break;
+ case EBADF:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ENOTSOCK:
+ PR_SetError(PR_NOT_SOCKET_ERROR, err);
+ break;
+ case EMSGSIZE:
+ case EINVAL:
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, err);
+ break;
+ case ENOBUFS:
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
+ break;
+ case ECONNREFUSED:
+ PR_SetError(PR_CONNECT_REFUSED_ERROR, err);
+ break;
+ case EISCONN:
+ PR_SetError(PR_IS_CONNECTED_ERROR, err);
+ break;
+ case SOCEFAULT:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_lseek_error(PRInt32 err)
+{
+ switch (err) {
+ case ERROR_INVALID_HANDLE:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ERROR_SEEK_ON_DEVICE:
+ PR_SetError(PR_IO_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_fsync_error(PRInt32 err)
+{
+ switch (err) {
+ case ERROR_ACCESS_DENIED:
+ case ERROR_WRITE_PROTECT:
+ PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err);
+ break;
+ case ERROR_INVALID_HANDLE:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_MORE_DATA:
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
+ break;
+ case ERROR_DISK_FULL:
+ case ERROR_HANDLE_DISK_FULL:
+ PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_close_error(PRInt32 err)
+{
+ switch (err) {
+ case ERROR_INVALID_HANDLE:
+ case EBADF:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ERROR_NOT_READY:
+ case ERROR_PATH_BUSY:
+ PR_SetError(PR_IO_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_socket_error(PRInt32 err)
+{
+ switch (err) {
+ case EPROTONOSUPPORT:
+ PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err);
+ break;
+ case EACCES:
+ PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err);
+ break;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_MORE_DATA:
+ case ENOBUFS:
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_recv_error(PRInt32 err)
+{
+ switch (err) {
+ case EWOULDBLOCK:
+ PR_SetError(PR_WOULD_BLOCK_ERROR, err);
+ break;
+ case EBADF:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ENOTSOCK:
+ PR_SetError(PR_NOT_SOCKET_ERROR, err);
+ break;
+ case SOCEFAULT:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case ERROR_NETNAME_DELETED:
+ PR_SetError(PR_CONNECT_RESET_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_recvfrom_error(PRInt32 err)
+{
+ switch (err) {
+ case EWOULDBLOCK:
+ PR_SetError(PR_WOULD_BLOCK_ERROR, err);
+ break;
+ case EBADF:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ENOTSOCK:
+ PR_SetError(PR_NOT_SOCKET_ERROR, err);
+ break;
+ case SOCEFAULT:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case ERROR_NETNAME_DELETED:
+ PR_SetError(PR_CONNECT_RESET_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_send_error(PRInt32 err)
+{
+ switch (err) {
+ case EWOULDBLOCK:
+ PR_SetError(PR_WOULD_BLOCK_ERROR, err);
+ break;
+ case EBADF:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ENOTSOCK:
+ PR_SetError(PR_NOT_SOCKET_ERROR, err);
+ break;
+ case EMSGSIZE:
+ case EINVAL:
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, err);
+ break;
+ case ENOBUFS:
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
+ break;
+ case ECONNREFUSED:
+ PR_SetError(PR_CONNECT_REFUSED_ERROR, err);
+ break;
+ case EISCONN:
+ PR_SetError(PR_IS_CONNECTED_ERROR, err);
+ break;
+ case SOCEFAULT:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case ERROR_NETNAME_DELETED:
+ PR_SetError(PR_CONNECT_RESET_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_sendto_error(PRInt32 err)
+{
+ switch (err) {
+ case EWOULDBLOCK:
+ PR_SetError(PR_WOULD_BLOCK_ERROR, err);
+ break;
+ case EBADF:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ENOTSOCK:
+ PR_SetError(PR_NOT_SOCKET_ERROR, err);
+ break;
+ case EMSGSIZE:
+ case EINVAL:
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, err);
+ break;
+ case ENOBUFS:
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
+ break;
+ case ECONNREFUSED:
+ PR_SetError(PR_CONNECT_REFUSED_ERROR, err);
+ break;
+ case EISCONN:
+ PR_SetError(PR_IS_CONNECTED_ERROR, err);
+ break;
+ case SOCEFAULT:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case ERROR_NETNAME_DELETED:
+ PR_SetError(PR_CONNECT_RESET_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_accept_error(PRInt32 err)
+{
+ switch (err) {
+ case EWOULDBLOCK:
+ PR_SetError(PR_WOULD_BLOCK_ERROR, err);
+ break;
+ case EBADF:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ENOTSOCK:
+ PR_SetError(PR_NOT_SOCKET_ERROR, err);
+ break;
+ case EOPNOTSUPP:
+ PR_SetError(PR_NOT_TCP_SOCKET_ERROR, err);
+ break;
+ case SOCEFAULT:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case EMFILE:
+ PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err);
+ break;
+ case ENOBUFS:
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_acceptex_error(PRInt32 err)
+{
+ switch (err) {
+ case ERROR_INVALID_HANDLE:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ERROR_INVALID_ADDRESS:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_MORE_DATA:
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_connect_error(PRInt32 err)
+{
+ switch (err) {
+ case EWOULDBLOCK:
+ PR_SetError(PR_WOULD_BLOCK_ERROR, err);
+ break;
+ case EINPROGRESS:
+ case EALREADY:
+ case EINVAL:
+ PR_SetError(PR_ALREADY_INITIATED_ERROR, err);
+ break;
+ case EBADF:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case EADDRNOTAVAIL:
+ PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err);
+ break;
+ case ENOTSOCK:
+ PR_SetError(PR_NOT_SOCKET_ERROR, err);
+ break;
+ case EAFNOSUPPORT:
+ PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err);
+ break;
+ case ETIMEDOUT:
+ PR_SetError(PR_IO_TIMEOUT_ERROR, err);
+ break;
+ case ECONNREFUSED:
+ PR_SetError(PR_CONNECT_REFUSED_ERROR, err);
+ break;
+ case ENETUNREACH:
+ PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, err);
+ break;
+ case EADDRINUSE:
+ PR_SetError(PR_ADDRESS_IN_USE_ERROR, err);
+ break;
+ case EISCONN:
+ PR_SetError(PR_IS_CONNECTED_ERROR, err);
+ break;
+ case SOCEFAULT:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_bind_error(PRInt32 err)
+{
+ switch (err) {
+ case EBADF:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ENOTSOCK:
+ PR_SetError(PR_NOT_SOCKET_ERROR, err);
+ break;
+ case SOCEFAULT:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case EADDRNOTAVAIL:
+ PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err);
+ break;
+ case EADDRINUSE:
+ PR_SetError(PR_ADDRESS_IN_USE_ERROR, err);
+ break;
+ case EACCES:
+ PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err);
+ break;
+ case EINVAL:
+ PR_SetError(PR_SOCKET_ADDRESS_IS_BOUND_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_listen_error(PRInt32 err)
+{
+ switch (err) {
+ case EBADF:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ENOTSOCK:
+ PR_SetError(PR_NOT_SOCKET_ERROR, err);
+ break;
+ case EOPNOTSUPP:
+ PR_SetError(PR_NOT_TCP_SOCKET_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_shutdown_error(PRInt32 err)
+{
+ switch (err) {
+ case EBADF:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ENOTSOCK:
+ PR_SetError(PR_NOT_SOCKET_ERROR, err);
+ break;
+ case ENOTCONN:
+ PR_SetError(PR_NOT_CONNECTED_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_getsockname_error(PRInt32 err)
+{
+ switch (err) {
+ case EBADF:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ENOTSOCK:
+ PR_SetError(PR_NOT_SOCKET_ERROR, err);
+ break;
+ case SOCEFAULT:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case ENOBUFS:
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_getpeername_error(PRInt32 err)
+{
+
+ switch (err) {
+ case EBADF:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ENOTSOCK:
+ PR_SetError(PR_NOT_SOCKET_ERROR, err);
+ break;
+ case ENOTCONN:
+ PR_SetError(PR_NOT_CONNECTED_ERROR, err);
+ break;
+ case SOCEFAULT:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case ENOBUFS:
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_getsockopt_error(PRInt32 err)
+{
+ switch (err) {
+ case EBADF:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ENOTSOCK:
+ PR_SetError(PR_NOT_SOCKET_ERROR, err);
+ break;
+ case ENOPROTOOPT:
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, err);
+ break;
+ case SOCEFAULT:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case EINVAL:
+ PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_setsockopt_error(PRInt32 err)
+{
+ switch (err) {
+ case EBADF:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ENOTSOCK:
+ PR_SetError(PR_NOT_SOCKET_ERROR, err);
+ break;
+ case ENOPROTOOPT:
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, err);
+ break;
+ case SOCEFAULT:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case EINVAL:
+ PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_open_error(PRInt32 err)
+{
+ switch (err) {
+ case ERROR_ALREADY_EXISTS:
+ case ERROR_FILE_EXISTS:
+ PR_SetError(PR_FILE_EXISTS_ERROR, err);
+ break;
+ case ERROR_FILE_NOT_FOUND:
+ PR_SetError(PR_FILE_NOT_FOUND_ERROR, err);
+ break;
+ case ERROR_ACCESS_DENIED:
+ PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err);
+ break;
+ case ERROR_INVALID_ADDRESS:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case ERROR_INVALID_NAME:
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, err);
+ break;
+ case ERROR_NOT_READY:
+ case ERROR_OPEN_FAILED:
+ case ERROR_PATH_BUSY:
+ PR_SetError(PR_IO_ERROR, err);
+ break;
+ case ERROR_DRIVE_LOCKED:
+ PR_SetError(PR_FILE_IS_LOCKED_ERROR, err);
+ break;
+ case ERROR_FILENAME_EXCED_RANGE:
+ PR_SetError(PR_NAME_TOO_LONG_ERROR, err);
+ break;
+ case ERROR_TOO_MANY_OPEN_FILES:
+ PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err);
+ break;
+ case ERROR_PATH_NOT_FOUND:
+ PR_SetError(PR_FILE_NOT_FOUND_ERROR, err);
+ break;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_MORE_DATA:
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
+ break;
+ case ERROR_DISK_FULL:
+ case ERROR_HANDLE_DISK_FULL:
+ PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err);
+ break;
+ case ERROR_WRITE_PROTECT:
+ PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_gethostname_error(PRInt32 err)
+{
+ switch (err) {
+ case SOCEFAULT:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case ENETDOWN:
+ case EINPROGRESS:
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
+
+void _MD_os2_map_select_error(PRInt32 err)
+{
+ PRErrorCode prerror;
+
+ switch (err) {
+ /*
+ * OS/2 select() only works on sockets. So in this
+ * context, ENOTSOCK is equivalent to EBADF on Unix.
+ */
+ case ENOTSOCK:
+ prerror = PR_BAD_DESCRIPTOR_ERROR;
+ break;
+ case EINVAL:
+ prerror = PR_INVALID_ARGUMENT_ERROR;
+ break;
+ case SOCEFAULT:
+ prerror = PR_ACCESS_FAULT_ERROR;
+ break;
+ default:
+ prerror = PR_UNKNOWN_ERROR;
+ }
+ PR_SetError(prerror, err);
+}
+
+void _MD_os2_map_lockf_error(PRInt32 err)
+{
+ switch (err) {
+ case ERROR_ACCESS_DENIED:
+ PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err);
+ break;
+ case ERROR_INVALID_HANDLE:
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+ break;
+ case ERROR_INVALID_ADDRESS:
+ PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+ break;
+ case ERROR_DRIVE_LOCKED:
+ case ERROR_LOCKED:
+ case ERROR_SHARING_VIOLATION:
+ PR_SetError(PR_FILE_IS_LOCKED_ERROR, err);
+ break;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_MORE_DATA:
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
+ break;
+ default:
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+ break;
+ }
+}
diff --git a/pr/src/md/os2/os2cv.c b/pr/src/md/os2/os2cv.c
new file mode 100644
index 00000000..34264dd5
--- /dev/null
+++ b/pr/src/md/os2/os2cv.c
@@ -0,0 +1,332 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+ * os2cv.c -- OS/2 Machine-Dependent Code for Condition Variables
+ *
+ * We implement our own condition variable wait queue. Each thread
+ * has a semaphore object (thread->md.blocked_sema) to block on while
+ * waiting on a condition variable.
+ *
+ * We use a deferred condition notify algorithm. When PR_NotifyCondVar
+ * or PR_NotifyAllCondVar is called, the condition notifies are simply
+ * recorded in the _MDLock structure. We defer the condition notifies
+ * until right after we unlock the lock. This way the awakened threads
+ * have a better chance to reaquire the lock.
+ */
+
+#include "primpl.h"
+
+/*
+ * AddThreadToCVWaitQueueInternal --
+ *
+ * Add the thread to the end of the condition variable's wait queue.
+ * The CV's lock must be locked when this function is called.
+ */
+
+static void
+AddThreadToCVWaitQueueInternal(PRThread *thred, struct _MDCVar *cv)
+{
+ PR_ASSERT((cv->waitTail != NULL && cv->waitHead != NULL)
+ || (cv->waitTail == NULL && cv->waitHead == NULL));
+ cv->nwait += 1;
+ thred->md.inCVWaitQueue = PR_TRUE;
+ thred->md.next = NULL;
+ thred->md.prev = cv->waitTail;
+ if (cv->waitHead == NULL) {
+ cv->waitHead = thred;
+ } else {
+ cv->waitTail->md.next = thred;
+ }
+ cv->waitTail = thred;
+}
+
+/*
+ * md_UnlockAndPostNotifies --
+ *
+ * Unlock the lock, and then do the deferred condition notifies.
+ * If waitThred and waitCV are not NULL, waitThred is added to
+ * the wait queue of waitCV before the lock is unlocked.
+ *
+ * This function is called by _PR_MD_WAIT_CV and _PR_MD_UNLOCK,
+ * the two places where a lock is unlocked.
+ */
+static void
+md_UnlockAndPostNotifies(
+ _MDLock *lock,
+ PRThread *waitThred,
+ _MDCVar *waitCV)
+{
+ PRIntn index;
+ _MDNotified post;
+ _MDNotified *notified, *prev = NULL;
+
+ /*
+ * Time to actually notify any conditions that were affected
+ * while the lock was held. Get a copy of the list that's in
+ * the lock structure and then zero the original. If it's
+ * linked to other such structures, we own that storage.
+ */
+ post = lock->notified; /* a safe copy; we own the lock */
+
+#if defined(DEBUG)
+ memset(&lock->notified, 0, sizeof(_MDNotified)); /* reset */
+#else
+ lock->notified.length = 0; /* these are really sufficient */
+ lock->notified.link = NULL;
+#endif
+
+ /*
+ * Figure out how many threads we need to wake up.
+ */
+ notified = &post; /* this is where we start */
+ do {
+ for (index = 0; index < notified->length; ++index) {
+ _MDCVar *cv = notified->cv[index].cv;
+ PRThread *thred;
+ int i;
+
+ /* Fast special case: no waiting threads */
+ if (cv->waitHead == NULL) {
+ notified->cv[index].notifyHead = NULL;
+ continue;
+ }
+
+ /* General case */
+ if (-1 == notified->cv[index].times) {
+ /* broadcast */
+ thred = cv->waitHead;
+ while (thred != NULL) {
+ thred->md.inCVWaitQueue = PR_FALSE;
+ thred = thred->md.next;
+ }
+ notified->cv[index].notifyHead = cv->waitHead;
+ cv->waitHead = cv->waitTail = NULL;
+ cv->nwait = 0;
+ } else {
+ thred = cv->waitHead;
+ i = notified->cv[index].times;
+ while (thred != NULL && i > 0) {
+ thred->md.inCVWaitQueue = PR_FALSE;
+ thred = thred->md.next;
+ i--;
+ }
+ notified->cv[index].notifyHead = cv->waitHead;
+ cv->waitHead = thred;
+ if (cv->waitHead == NULL) {
+ cv->waitTail = NULL;
+ } else {
+ if (cv->waitHead->md.prev != NULL) {
+ cv->waitHead->md.prev->md.next = NULL;
+ cv->waitHead->md.prev = NULL;
+ }
+ }
+ cv->nwait -= notified->cv[index].times - i;
+ }
+ }
+ notified = notified->link;
+ } while (NULL != notified);
+
+ if (waitThred) {
+ AddThreadToCVWaitQueueInternal(waitThred, waitCV);
+ }
+
+ /* Release the lock before notifying */
+ LeaveCriticalSection(&lock->mutex);
+
+ notified = &post; /* this is where we start */
+ do {
+ for (index = 0; index < notified->length; ++index) {
+ PRThread *thred;
+ PRThread *next;
+
+ thred = notified->cv[index].notifyHead;
+ while (thred != NULL) {
+ BOOL rv;
+
+ next = thred->md.next;
+ thred->md.prev = thred->md.next = NULL;
+ rv = DosPostEventSem(thred->md.blocked_sema.sem);
+ PR_ASSERT(rv == NO_ERROR);
+ thred = next;
+ }
+ }
+ prev = notified;
+ notified = notified->link;
+ if (&post != prev) PR_DELETE(prev);
+ } while (NULL != notified);
+}
+
+/*
+ * Notifies just get posted to the protecting mutex. The
+ * actual notification is done when the lock is released so that
+ * MP systems don't contend for a lock that they can't have.
+ */
+static void md_PostNotifyToCvar(_MDCVar *cvar, _MDLock *lock,
+ PRBool broadcast)
+{
+ PRIntn index = 0;
+ _MDNotified *notified = &lock->notified;
+
+ while (1) {
+ for (index = 0; index < notified->length; ++index) {
+ if (notified->cv[index].cv == cvar) {
+ if (broadcast) {
+ notified->cv[index].times = -1;
+ } else if (-1 != notified->cv[index].times) {
+ notified->cv[index].times += 1;
+ }
+ return;
+ }
+ }
+ /* if not full, enter new CV in this array */
+ if (notified->length < _MD_CV_NOTIFIED_LENGTH) break;
+
+ /* if there's no link, create an empty array and link it */
+ if (NULL == notified->link) {
+ notified->link = PR_NEWZAP(_MDNotified);
+ }
+
+ notified = notified->link;
+ }
+
+ /* A brand new entry in the array */
+ notified->cv[index].times = (broadcast) ? -1 : 1;
+ notified->cv[index].cv = cvar;
+ notified->length += 1;
+}
+
+/*
+ * _PR_MD_NEW_CV() -- Creating new condition variable
+ * ... Solaris uses cond_init() in similar function.
+ *
+ * returns: -1 on failure
+ * 0 when it succeeds.
+ *
+ */
+PR_IMPLEMENT(PRInt32)
+_PR_MD_NEW_CV(_MDCVar *cv)
+{
+ cv->magic = _MD_MAGIC_CV;
+ /*
+ * The waitHead, waitTail, and nwait fields are zeroed
+ * when the PRCondVar structure is created.
+ */
+ return 0;
+}
+
+PR_IMPLEMENT(void) _PR_MD_FREE_CV(_MDCVar *cv)
+{
+ cv->magic = (PRUint32)-1;
+ return;
+}
+
+/*
+ * _PR_MD_WAIT_CV() -- Wait on condition variable
+ */
+PR_IMPLEMENT(void)
+_PR_MD_WAIT_CV(_MDCVar *cv, _MDLock *lock, PRIntervalTime timeout )
+{
+ PRThread *thred = _PR_MD_CURRENT_THREAD();
+ ULONG rv, count;
+ ULONG msecs = (timeout == PR_INTERVAL_NO_TIMEOUT) ?
+ SEM_INDEFINITE_WAIT : PR_IntervalToMilliseconds(timeout);
+
+ /*
+ * If we have pending notifies, post them now.
+ */
+ if (0 != lock->notified.length) {
+ md_UnlockAndPostNotifies(lock, thred, cv);
+ } else {
+ AddThreadToCVWaitQueueInternal(thred, cv);
+ LeaveCriticalSection(&lock->mutex);
+ }
+
+ /* Wait for notification or timeout; don't really care which */
+ rv = DosWaitEventSem(thred->md.blocked_sema.sem, msecs);
+ DosResetEventSem(thred->md.blocked_sema.sem, &count);
+
+ EnterCriticalSection(&(lock->mutex));
+
+ PR_ASSERT(rv == NO_ERROR || rv == ERROR_TIMEOUT);
+
+ if(rv == ERROR_TIMEOUT)
+ {
+ if (thred->md.inCVWaitQueue) {
+ PR_ASSERT((cv->waitTail != NULL && cv->waitHead != NULL)
+ || (cv->waitTail == NULL && cv->waitHead == NULL));
+ cv->nwait -= 1;
+ thred->md.inCVWaitQueue = PR_FALSE;
+ if (cv->waitHead == thred) {
+ cv->waitHead = thred->md.next;
+ if (cv->waitHead == NULL) {
+ cv->waitTail = NULL;
+ } else {
+ cv->waitHead->md.prev = NULL;
+ }
+ } else {
+ PR_ASSERT(thred->md.prev != NULL);
+ thred->md.prev->md.next = thred->md.next;
+ if (thred->md.next != NULL) {
+ thred->md.next->md.prev = thred->md.prev;
+ } else {
+ PR_ASSERT(cv->waitTail == thred);
+ cv->waitTail = thred->md.prev;
+ }
+ }
+ thred->md.next = thred->md.prev = NULL;
+ } else {
+ /*
+ * This thread must have been notified, but the
+ * SemRelease call happens after SemRequest
+ * times out. Wait on the semaphore again to make it
+ * non-signaled. We assume this wait won't take long.
+ */
+ rv = DosWaitEventSem(thred->md.blocked_sema.sem, SEM_INDEFINITE_WAIT);
+ DosResetEventSem(thred->md.blocked_sema.sem, &count);
+ PR_ASSERT(rv == NO_ERROR);
+ }
+ }
+ PR_ASSERT(thred->md.inCVWaitQueue == PR_FALSE);
+ return;
+} /* --- end _PR_MD_WAIT_CV() --- */
+
+PR_IMPLEMENT(void)
+_PR_MD_NOTIFY_CV(_MDCVar *cv, _MDLock *lock)
+{
+ md_PostNotifyToCvar(cv, lock, PR_FALSE);
+ return;
+}
+
+PR_IMPLEMENT(void)
+_PR_MD_NOTIFYALL_CV(_MDCVar *cv, _MDLock *lock)
+{
+ md_PostNotifyToCvar(cv, lock, PR_TRUE);
+ return;
+}
+
+PR_IMPLEMENT(void)
+_PR_MD_UNLOCK(_MDLock *lock)
+{
+ if (0 != lock->notified.length) {
+ md_UnlockAndPostNotifies(lock, NULL, NULL);
+ } else {
+ LeaveCriticalSection(&lock->mutex);
+ }
+ return;
+}
diff --git a/pr/src/md/os2/os2gc.c b/pr/src/md/os2/os2gc.c
new file mode 100644
index 00000000..00db7e15
--- /dev/null
+++ b/pr/src/md/os2/os2gc.c
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+ * GC related routines
+ *
+ */
+#include "primpl.h"
+
+extern APIRET (* APIENTRY QueryThreadContext)(TID, ULONG, PCONTEXTRECORD);
+
+PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
+{
+ CONTEXTRECORD context;
+ context.ContextFlags = CONTEXT_INTEGER;
+
+ if (_PR_IS_NATIVE_THREAD(t)) {
+ context.ContextFlags |= CONTEXT_CONTROL;
+ if (QueryThreadContext(t->md.handle, CONTEXT_CONTROL, &context)) {
+ t->md.gcContext[0] = context.ctx_RegEax;
+ t->md.gcContext[1] = context.ctx_RegEbx;
+ t->md.gcContext[2] = context.ctx_RegEcx;
+ t->md.gcContext[3] = context.ctx_RegEdx;
+ t->md.gcContext[4] = context.ctx_RegEsi;
+ t->md.gcContext[5] = context.ctx_RegEdi;
+ t->md.gcContext[6] = context.ctx_RegEsp;
+ t->md.gcContext[7] = context.ctx_RegEbp;
+ *np = PR_NUM_GCREGS;
+ } else {
+ PR_ASSERT(0);/* XXX */
+ }
+ }
+ return (PRWord *)&t->md.gcContext;
+}
+
+/* This function is not used right now, but is left as a reference.
+ * If you ever need to get the fiberID from the currently running fiber,
+ * this is it.
+ */
+void *
+GetMyFiberID()
+{
+ void *fiberData = 0;
+
+ /* A pointer to our tib entry is found at FS:[18]
+ * At offset 10h is the fiberData pointer. The context of the
+ * fiber is stored in there.
+ */
+#ifdef HAVE_ASM
+ __asm {
+ mov EDX, FS:[18h]
+ mov EAX, DWORD PTR [EDX+10h]
+ mov [fiberData], EAX
+ }
+#endif
+
+ return fiberData;
+}
diff --git a/pr/src/md/os2/os2inrval.c b/pr/src/md/os2/os2inrval.c
new file mode 100644
index 00000000..a204a639
--- /dev/null
+++ b/pr/src/md/os2/os2inrval.c
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+ * OS/2 interval timers
+ *
+ */
+
+#include "primpl.h"
+
+ULONG _os2_ticksPerSec = -1;
+PRIntn _os2_bitShift = 0;
+PRInt32 _os2_highMask = 0;
+
+
+
+PR_IMPLEMENT(void)
+_PR_MD_INTERVAL_INIT()
+{
+ ULONG count;
+
+ if (DosTmrQueryFreq(&_os2_ticksPerSec) == NO_ERROR)
+ {
+ while(_os2_ticksPerSec > PR_INTERVAL_MAX) {
+ _os2_ticksPerSec >>= 1;
+ _os2_bitShift++;
+ _os2_highMask = (_os2_highMask << 1)+1;
+ }
+ }
+ else
+ _os2_ticksPerSec = -1;
+
+ PR_ASSERT(_os2_ticksPerSec > PR_INTERVAL_MIN && _os2_ticksPerSec < PR_INTERVAL_MAX);
+}
+
+PR_IMPLEMENT(PRIntervalTime)
+_PR_MD_GET_INTERVAL()
+{
+ QWORD count;
+
+ /* Sadly; nspr requires the interval to range from 1000 ticks per second
+ * to only 100000 ticks per second; Counter is too high
+ * resolution...
+ */
+ if (DosTmrQueryTime(&count) == NO_ERROR) {
+ PRInt32 top = count.ulHi & _os2_highMask;
+ top = top << (32 - _os2_bitShift);
+ count.ulLo = count.ulLo >> _os2_bitShift;
+ count.ulHi = count.ulLo + top;
+ return (PRUint32)count.ulLo;
+ }
+ else{
+ ULONG msCount = PR_FAILURE;
+ DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &msCount, sizeof(msCount));
+ return msCount;
+ }
+}
+
+PR_IMPLEMENT(PRIntervalTime)
+_PR_MD_INTERVAL_PER_SEC()
+{
+ if(_os2_ticksPerSec != -1)
+ return _os2_ticksPerSec;
+ else
+ return 1000;
+}
diff --git a/pr/src/md/os2/os2io.c b/pr/src/md/os2/os2io.c
new file mode 100644
index 00000000..b2e89d27
--- /dev/null
+++ b/pr/src/md/os2/os2io.c
@@ -0,0 +1,620 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/* OS2 IO module
+ *
+ * Assumes synchronous I/O.
+ *
+ */
+
+#include "primpl.h"
+#include <direct.h>
+
+struct _MDLock _pr_ioq_lock;
+
+PR_IMPLEMENT(PRStatus)
+_PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks)
+{
+ PRInt32 rv;
+ ULONG count;
+
+ PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
+ SEM_INDEFINITE_WAIT : PR_IntervalToMilliseconds(ticks);
+ rv = DosWaitEventSem(thread->md.blocked_sema.sem, msecs);
+ DosResetEventSem(thread->md.blocked_sema.sem, &count);
+ switch(rv)
+ {
+ case NO_ERROR:
+ return PR_SUCCESS;
+ break;
+ case ERROR_TIMEOUT:
+ _PR_THREAD_LOCK(thread);
+ if (thread->state == _PR_IO_WAIT) {
+ ;
+ } else {
+ if (thread->wait.cvar != NULL) {
+ thread->wait.cvar = NULL;
+ _PR_THREAD_UNLOCK(thread);
+ } else {
+ /* The CVAR was notified just as the timeout
+ * occurred. This led to us being notified twice.
+ * call SemRequest() to clear the semaphore.
+ */
+ _PR_THREAD_UNLOCK(thread);
+ rv = DosWaitEventSem(thread->md.blocked_sema.sem, 0);
+ DosResetEventSem(thread->md.blocked_sema.sem, &count);
+ PR_ASSERT(rv == NO_ERROR);
+ }
+ }
+ return PR_SUCCESS;
+ break;
+ default:
+ break;
+ }
+ return PR_FAILURE;
+}
+PR_IMPLEMENT(PRStatus)
+_PR_MD_WAKEUP_WAITER(PRThread *thread)
+{
+ if ( _PR_IS_NATIVE_THREAD(thread) )
+ {
+ if (DosPostEventSem(thread->md.blocked_sema.sem) != NO_ERROR)
+ return PR_FAILURE;
+ else
+ return PR_SUCCESS;
+ }
+}
+
+
+/* --- FILE IO ----------------------------------------------------------- */
+/*
+ * _PR_MD_OPEN() -- Open a file
+ *
+ * returns: a fileHandle
+ *
+ * The NSPR open flags (osflags) are translated into flags for OS/2
+ *
+ * Mode seems to be passed in as a unix style file permissions argument
+ * as in 0666, in the case of opening the logFile.
+ *
+ */
+PRInt32
+_PR_MD_OPEN(const char *name, PRIntn osflags, int mode)
+{
+ HFILE file;
+ PRInt32 access = OPEN_SHARE_DENYNONE;
+ PRInt32 flags = OPEN_ACTION_OPEN_IF_EXISTS;
+ PRInt32 rc;
+ PRUword actionTaken;
+
+ ULONG CurMaxFH = 0;
+ LONG ReqCount = 1;
+
+ if (osflags & PR_RDONLY)
+ access |= OPEN_ACCESS_READONLY;
+ else if (osflags & PR_WRONLY)
+ access |= OPEN_ACCESS_WRITEONLY;
+ else if(osflags & PR_RDWR)
+ access |= OPEN_ACCESS_READWRITE;
+ if (osflags & PR_CREATE_FILE)
+ flags |= OPEN_ACTION_CREATE_IF_NEW;
+ else if (osflags & PR_TRUNCATE){
+ flags &= ~OPEN_ACTION_OPEN_IF_EXISTS;
+ flags |= OPEN_ACTION_REPLACE_IF_EXISTS;
+ }
+
+ /* OS/2 sets the Max file handles per process to 20 by default */
+ DosSetRelMaxFH(&ReqCount, &CurMaxFH);
+
+ rc = DosOpen((char*)name,
+ &file, /* file handle if successful */
+ &actionTaken, /* reason for failure */
+ 0, /* initial size of new file */
+ FILE_NORMAL, /* file system attributes */
+ flags, /* Open flags */
+ access, /* Open mode and rights */
+ 0); /* OS/2 Extended Attributes */
+ if (rc != NO_ERROR) {
+ _PR_MD_MAP_OPEN_ERROR(rc);
+ return -1;
+ }
+
+ return (PRInt32)file;
+}
+
+PRInt32
+_PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len)
+{
+ PRUword bytes;
+ int rv;
+
+ rv = DosRead((HFILE)fd->secret->md.osfd,
+ (PVOID)buf,
+ len,
+ &bytes);
+
+ if (rv != NO_ERROR)
+ {
+ /* ERROR_HANDLE_EOF can only be returned by async io */
+ PR_ASSERT(rv != ERROR_HANDLE_EOF);
+ if (rv == ERROR_BROKEN_PIPE)
+ return 0;
+ else {
+ _PR_MD_MAP_READ_ERROR(rv);
+ return -1;
+ }
+ }
+ return bytes;
+}
+
+PRInt32
+_PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len)
+{
+ PRUword bytes;
+ int rv;
+
+ /* No longer using DosWrite since it doesn't convert \n to \n\r like C runtime does */
+#if 0
+ rv = DosWrite((HFILE)fd->secret->md.osfd,
+ (PVOID)buf,
+ len,
+ &bytes);
+
+ if (rv != NO_ERROR)
+ {
+ _PR_MD_MAP_WRITE_ERROR(rv);
+ return -1;
+ }
+#else
+ bytes = write(fd->secret->md.osfd, buf, len);
+ if (rv == -1)
+ _PR_MD_MAP_WRITE_ERROR(errno);
+#endif
+
+ return bytes;
+} /* --- end _PR_MD_WRITE() --- */
+
+PRInt32
+_PR_MD_LSEEK(PRFileDesc *fd, PRInt32 offset, int whence)
+{
+ PRInt32 rv;
+ PRUword newLocation;
+
+ rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, offset, whence, &newLocation);
+
+ if (rv != NO_ERROR) {
+ _PR_MD_MAP_LSEEK_ERROR(rv);
+ return -1;
+ } else
+ return newLocation;
+}
+
+PRInt64
+_PR_MD_LSEEK64(PRFileDesc *fd, PRInt64 offset, int whence)
+{
+ PRInt64 result;
+ PRInt32 rv, low = offset.lo, hi = offset.hi;
+ PRUword newLocation;
+
+ rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, low, whence, &newLocation);
+ rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, hi, FILE_CURRENT, &newLocation);
+
+ if (rv != NO_ERROR) {
+ _PR_MD_MAP_LSEEK_ERROR(rv);
+ hi = newLocation = -1;
+ }
+
+ result.lo = hi;
+ result.hi = newLocation;
+ return result;
+}
+
+PRInt32
+_PR_MD_FSYNC(PRFileDesc *fd)
+{
+ PRInt32 rc = DosResetBuffer((HFILE)fd->secret->md.osfd);
+
+ if (rc != NO_ERROR) {
+ if (rc != ERROR_ACCESS_DENIED) {
+ _PR_MD_MAP_FSYNC_ERROR(rc);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+PRInt32
+_MD_CloseFile(PRInt32 osfd)
+{
+ PRInt32 rv;
+
+ rv = DosClose((HFILE)osfd);
+ if (rv != NO_ERROR)
+ _PR_MD_MAP_CLOSE_ERROR(rv);
+ return rv;
+}
+
+
+/* --- DIR IO ------------------------------------------------------------ */
+#define GetFileFromDIR(d) (d)->d_entry.achName
+
+void FlipSlashes(char *cp, int len)
+{
+ while (--len >= 0) {
+ if (cp[0] == '/') {
+ cp[0] = PR_DIRECTORY_SEPARATOR;
+ }
+ cp++;
+ }
+}
+
+/*
+**
+** Local implementations of standard Unix RTL functions which are not provided
+** by the VAC RTL.
+**
+*/
+
+PRInt32
+_PR_MD_CLOSE_DIR(_MDDir *d)
+{
+ PRInt32 rc;
+
+ if ( d ) {
+ rc = DosFindClose(d->d_hdl);
+ if(rc == NO_ERROR){
+ d->magic = (PRUint32)-1;
+ return PR_SUCCESS;
+ } else {
+ _PR_MD_MAP_CLOSEDIR_ERROR(rc);
+ return PR_FAILURE;
+ }
+ }
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return PR_FAILURE;
+}
+
+
+PRStatus
+_PR_MD_OPEN_DIR(_MDDir *d, const char *name)
+{
+ char filename[ CCHMAXPATH ];
+ PRUword numEntries, rc;
+
+ PR_snprintf(filename, CCHMAXPATH, "%s%s%s",
+ name, PR_DIRECTORY_SEPARATOR_STR, "*.*");
+ FlipSlashes( filename, strlen(filename) );
+
+ d->d_hdl = HDIR_CREATE;
+
+ rc = DosFindFirst( filename, &d->d_hdl, FILE_DIRECTORY, &(d->d_entry), sizeof(d->d_entry), &numEntries, FIL_STANDARD);
+ if ( rc != NO_ERROR ) {
+ _PR_MD_MAP_OPENDIR_ERROR(rc);
+ return PR_FAILURE;
+ }
+ d->firstEntry = PR_TRUE;
+ d->magic = _MD_MAGIC_DIR;
+ return PR_SUCCESS;
+}
+
+char *
+_PR_MD_READ_DIR(_MDDir *d, PRIntn flags)
+{
+ PRUword numFiles = 1;
+ BOOL rv;
+ char *fileName;
+
+ if ( d ) {
+ while (1) {
+ if (d->firstEntry) {
+ d->firstEntry = PR_FALSE;
+ rv = NO_ERROR;
+ } else {
+ rv = DosFindNext(d->d_hdl, &(d->d_entry), sizeof(d->d_entry), &numFiles);
+ }
+ if (rv != NO_ERROR) {
+ break;
+ }
+ fileName = GetFileFromDIR(d);
+ if ( (flags & PR_SKIP_DOT) &&
+ (fileName[0] == '.') && (fileName[1] == '\0'))
+ continue;
+ if ( (flags & PR_SKIP_DOT_DOT) &&
+ (fileName[0] == '.') && (fileName[1] == '.') &&
+ (fileName[2] == '\0'))
+ continue;
+ /*
+ * XXX
+ * Is this the correct definition of a hidden file on OS/2?
+ */
+ if ( (flags & PR_SKIP_HIDDEN) && (fileName[0] == '.'))
+ continue;
+ return fileName;
+ }
+ PR_ASSERT(NO_ERROR != rv);
+ _PR_MD_MAP_READDIR_ERROR(rv);
+ return NULL;
+ }
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return NULL;
+}
+
+PRInt32
+_PR_MD_DELETE(const char *name)
+{
+ PRInt32 rc = DosDelete((char*)name);
+ if(rc == NO_ERROR) {
+ return 0;
+ } else {
+ _PR_MD_MAP_DELETE_ERROR(rc);
+ return -1;
+ }
+}
+
+PRInt32
+_PR_MD_STAT(const char *fn, struct stat *info)
+{
+ PRInt32 rv;
+
+ rv = _stat((char*)fn, info);
+ if (-1 == rv) {
+ /*
+ * Check for MSVC runtime library _stat() bug.
+ * (It's really a bug in FindFirstFile().)
+ * If a pathname ends in a backslash or slash,
+ * e.g., c:\temp\ or c:/temp/, _stat() will fail.
+ * Note: a pathname ending in a slash (e.g., c:/temp/)
+ * can be handled by _stat() on NT but not on Win95.
+ *
+ * We remove the backslash or slash at the end and
+ * try again.
+ *
+ * Not sure if this happens on OS/2 or not,
+ * but it doesn't hurt to be careful.
+ */
+
+ int len = strlen(fn);
+ if (len > 0 && len <= _MAX_PATH
+ && (fn[len - 1] == '\\' || fn[len - 1] == '/')) {
+ char newfn[_MAX_PATH + 1];
+
+ strcpy(newfn, fn);
+ newfn[len - 1] = '\0';
+ rv = _stat(newfn, info);
+ }
+ }
+
+ if (-1 == rv) {
+ _PR_MD_MAP_STAT_ERROR(errno);
+ }
+ return rv;
+}
+
+PRInt32
+_PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info)
+{
+ struct stat sb;
+ PRInt32 rv;
+
+ if ( (rv = _PR_MD_STAT(fn, &sb)) == 0 ) {
+ if (info) {
+ if (S_IFREG & sb.st_mode)
+ info->type = PR_FILE_FILE ;
+ else if (S_IFDIR & sb.st_mode)
+ info->type = PR_FILE_DIRECTORY;
+ else
+ info->type = PR_FILE_OTHER;
+ info->size = sb.st_size;
+ info->modifyTime.lo = sb.st_mtime;
+ info->creationTime.lo = sb.st_ctime;
+ }
+ }
+ return rv;
+}
+
+PRInt32
+_PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info)
+{
+ PRFileInfo info32;
+ PRInt32 rv = _PR_MD_GETFILEINFO(fn, &info32);
+ if (0 == rv)
+ {
+ info->type = info32.type;
+ info->size.lo = info32.size;
+ info->modifyTime = info32.modifyTime;
+ info->creationTime = info32.creationTime;
+ }
+ return rv;
+}
+
+PRInt32
+_PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info)
+{
+ /* For once, the VAC compiler/library did a nice thing.
+ * The file handle used by the C runtime is the same one
+ * returned by the OS when you call DosOpen(). This means
+ * that you can take an OS HFILE and use it with C file
+ * functions. The only caveat is that you have to call
+ * _setmode() first to initialize some junk. This is
+ * immensely useful because I did not have a clue how to
+ * implement this function otherwise. The windows folks
+ * took the source from the Microsoft C library source, but
+ * IBM wasn't kind enough to ship the source with VAC.
+ * On second thought, the needed function could probably
+ * be gotten from the OS/2 GNU library source, but the
+ * point is now moot.
+ */
+ struct stat hinfo;
+
+ _setmode(fd->secret->md.osfd, O_BINARY);
+ if(fstat((int)fd->secret->md.osfd, &hinfo) != NO_ERROR) {
+ _PR_MD_MAP_FSTAT_ERROR(errno);
+ return -1;
+ }
+
+ if (hinfo.st_mode & S_IFDIR)
+ info->type = PR_FILE_DIRECTORY;
+ else
+ info->type = PR_FILE_FILE;
+
+ info->size = hinfo.st_size;
+ info->modifyTime.lo = hinfo.st_mtime;
+ info->creationTime.lo = hinfo.st_ctime;
+
+ return 0;
+}
+
+PRInt32
+_PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info)
+{
+ PRFileInfo info32;
+ PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, &info32);
+ if (0 == rv)
+ {
+ info->type = info32.type;
+ info->size.lo = info32.size;
+ info->modifyTime = info32.modifyTime;
+ info->creationTime = info32.creationTime;
+ }
+ return rv;
+}
+
+
+PRInt32
+_PR_MD_RENAME(const char *from, const char *to)
+{
+ PRInt32 rc;
+ /* Does this work with dot-relative pathnames? */
+ if ( (rc = DosMove((char *)from, (char *)to)) == NO_ERROR) {
+ return 0;
+ } else {
+ _PR_MD_MAP_RENAME_ERROR(rc);
+ return -1;
+ }
+}
+
+PRInt32
+_PR_MD_ACCESS(const char *name, PRIntn how)
+{
+PRInt32 rv;
+ switch (how) {
+ case PR_ACCESS_WRITE_OK:
+ rv = access(name, 02);
+ break;
+ case PR_ACCESS_READ_OK:
+ rv = access(name, 04);
+ break;
+ case PR_ACCESS_EXISTS:
+ return access(name, 00);
+ break;
+ default:
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return -1;
+ }
+ if (rv < 0)
+ _PR_MD_MAP_ACCESS_ERROR(errno);
+ return rv;
+}
+
+PRInt32
+_PR_MD_MKDIR(const char *name, PRIntn mode)
+{
+ PRInt32 rc;
+ /* XXXMB - how to translate the "mode"??? */
+ if ((rc = DosCreateDir((char *)name, NULL)) == NO_ERROR) {
+ return 0;
+ } else {
+ _PR_MD_MAP_MKDIR_ERROR(rc);
+ return -1;
+ }
+}
+
+PRInt32
+_PR_MD_RMDIR(const char *name)
+{
+ PRInt32 rc;
+ if ( (rc = DosDeleteDir((char *)name)) == NO_ERROR) {
+ return 0;
+ } else {
+ _PR_MD_MAP_RMDIR_ERROR(rc);
+ return -1;
+ }
+}
+
+PR_IMPLEMENT(PRStatus)
+_PR_MD_LOCKFILE(PRInt32 f)
+{
+ PRInt32 rv;
+ FILELOCK lock, unlock;
+
+ lock.lOffset = 0;
+ lock.lRange = 0xffffffff;
+ unlock.lOffset = 0;
+ unlock.lRange = 0;
+
+ /*
+ * loop trying to DosSetFileLocks(),
+ * pause for a few miliseconds when can't get the lock
+ * and try again
+ */
+ for( rv = FALSE; rv == FALSE; /* do nothing */ )
+ {
+
+ rv = DosSetFileLocks( (HFILE) f,
+ &unlock, &lock,
+ 0, 0);
+ if ( rv != NO_ERROR )
+ {
+ DosSleep( 50 ); /* Sleep() a few milisecs and try again. */
+ }
+ } /* end for() */
+ return PR_SUCCESS;
+} /* end _PR_MD_LOCKFILE() */
+
+PR_IMPLEMENT(PRStatus)
+_PR_MD_TLOCKFILE(PRInt32 f)
+{
+ return _PR_MD_LOCKFILE(f);
+} /* end _PR_MD_TLOCKFILE() */
+
+
+PR_IMPLEMENT(PRStatus)
+_PR_MD_UNLOCKFILE(PRInt32 f)
+{
+ PRInt32 rv;
+ FILELOCK lock, unlock;
+
+ lock.lOffset = 0;
+ lock.lRange = 0;
+ unlock.lOffset = 0;
+ unlock.lRange = 0xffffffff;
+
+ rv = DosSetFileLocks( (HFILE) f,
+ &unlock, &lock,
+ 0, 0);
+
+ if ( rv != NO_ERROR )
+ {
+ return PR_SUCCESS;
+ }
+ else
+ {
+ return PR_FAILURE;
+ }
+} /* end _PR_MD_UNLOCKFILE() */
+
diff --git a/pr/src/md/os2/os2misc.c b/pr/src/md/os2/os2misc.c
new file mode 100644
index 00000000..00913013
--- /dev/null
+++ b/pr/src/md/os2/os2misc.c
@@ -0,0 +1,513 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+ * os2misc.c
+ *
+ */
+#include "primpl.h"
+
+PR_IMPLEMENT(char *)
+_PR_MD_GET_ENV(const char *name)
+{
+ return getenv(name);
+}
+
+PR_IMPLEMENT(PRIntn)
+_PR_MD_PUT_ENV(const char *name)
+{
+ return putenv(name);
+}
+
+
+/*
+ **************************************************************************
+ **************************************************************************
+ **
+ ** Date and time routines
+ **
+ **************************************************************************
+ **************************************************************************
+ */
+
+#include <sys/timeb.h>
+/*
+ *-----------------------------------------------------------------------
+ *
+ * PR_Now --
+ *
+ * Returns the current time in microseconds since the epoch.
+ * The epoch is midnight January 1, 1970 GMT.
+ * The implementation is machine dependent. This is the
+ * implementation for OS/2.
+ * Cf. time_t time(time_t *tp)
+ *
+ *-----------------------------------------------------------------------
+ */
+
+PR_IMPLEMENT(PRTime)
+PR_Now(void)
+{
+ PRInt64 s, ms, ms2us, s2us;
+ struct timeb b;
+
+ ftime(&b);
+ LL_I2L(ms2us, PR_USEC_PER_MSEC);
+ LL_I2L(s2us, PR_USEC_PER_SEC);
+ LL_I2L(s, b.time);
+ LL_I2L(ms, b.millitm);
+ LL_MUL(ms, ms, ms2us);
+ LL_MUL(s, s, s2us);
+ LL_ADD(s, s, ms);
+ return s;
+}
+
+
+/*
+ ***********************************************************************
+ ***********************************************************************
+ *
+ * Process creation routines
+ *
+ ***********************************************************************
+ ***********************************************************************
+ */
+
+/*
+ * Assemble the command line by concatenating the argv array.
+ * On success, this function returns 0 and the resulting command
+ * line is returned in *cmdLine. On failure, it returns -1.
+ */
+static int assembleCmdLine(char *const *argv, char **cmdLine)
+{
+ char *const *arg;
+ char *p, *q;
+ int cmdLineSize;
+ int numBackslashes;
+ int i;
+ int argNeedQuotes;
+
+ /*
+ * Find out how large the command line buffer should be.
+ */
+ cmdLineSize = 0;
+ for (arg = argv; *arg; arg++) {
+ /*
+ * \ and " need to be escaped by a \. In the worst case,
+ * every character is a \ or ", so the string of length
+ * may double. If we quote an argument, that needs two ".
+ * Finally, we need a space between arguments, a null between
+ * the EXE name and the arguments, and 2 nulls at the end
+ * of command line.
+ */
+ cmdLineSize += 2 * strlen(*arg) /* \ and " need to be escaped */
+ + 2 /* we quote every argument */
+ + 4; /* space in between, or final nulls */
+ }
+ p = *cmdLine = PR_MALLOC(cmdLineSize);
+ if (p == NULL) {
+ return -1;
+ }
+
+ for (arg = argv; *arg; arg++) {
+ /* Add a space to separates the arguments */
+ if (arg > argv + 1) {
+ *p++ = ' ';
+ }
+ q = *arg;
+ numBackslashes = 0;
+ argNeedQuotes = 0;
+
+ /* If the argument contains white space, it needs to be quoted. */
+ if (strpbrk(*arg, " \f\n\r\t\v")) {
+ argNeedQuotes = 1;
+ }
+
+ if (argNeedQuotes) {
+ *p++ = '"';
+ }
+ while (*q) {
+ if (*q == '\\') {
+ numBackslashes++;
+ q++;
+ } else if (*q == '"') {
+ if (numBackslashes) {
+ /*
+ * Double the backslashes since they are followed
+ * by a quote
+ */
+ for (i = 0; i < 2 * numBackslashes; i++) {
+ *p++ = '\\';
+ }
+ numBackslashes = 0;
+ }
+ /* To escape the quote */
+ *p++ = '\\';
+ *p++ = *q++;
+ } else {
+ if (numBackslashes) {
+ /*
+ * Backslashes are not followed by a quote, so
+ * don't need to double the backslashes.
+ */
+ for (i = 0; i < numBackslashes; i++) {
+ *p++ = '\\';
+ }
+ numBackslashes = 0;
+ }
+ *p++ = *q++;
+ }
+ }
+
+ /* Now we are at the end of this argument */
+ if (numBackslashes) {
+ /*
+ * Double the backslashes if we have a quote string
+ * delimiter at the end.
+ */
+ if (argNeedQuotes) {
+ numBackslashes *= 2;
+ }
+ for (i = 0; i < numBackslashes; i++) {
+ *p++ = '\\';
+ }
+ }
+ if (argNeedQuotes) {
+ *p++ = '"';
+ }
+ if(arg == argv)
+ *p++ = '\0';
+ }
+
+ /* Add 2 nulls at the end */
+ *p++ = '\0';
+ *p = '\0';
+ return 0;
+}
+
+/*
+ * Assemble the environment block by concatenating the envp array
+ * (preserving the terminating null byte in each array element)
+ * and adding a null byte at the end.
+ *
+ * Returns 0 on success. The resulting environment block is returned
+ * in *envBlock. Note that if envp is NULL, a NULL pointer is returned
+ * in *envBlock. Returns -1 on failure.
+ */
+static int assembleEnvBlock(char **envp, char **envBlock)
+{
+ char *p;
+ char *q;
+ char **env;
+ char *curEnv;
+ char *cwdStart, *cwdEnd;
+ int envBlockSize;
+
+ PPIB ppib = NULL;
+ PTIB ptib = NULL;
+
+ if (envp == NULL) {
+ *envBlock = NULL;
+ return 0;
+ }
+
+ if(DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR)
+ return -1;
+
+ curEnv = ppib->pib_pchenv;
+
+ cwdStart = curEnv;
+ while (*cwdStart) {
+ if (cwdStart[0] == '=' && cwdStart[1] != '\0'
+ && cwdStart[2] == ':' && cwdStart[3] == '=') {
+ break;
+ }
+ cwdStart += strlen(cwdStart) + 1;
+ }
+ cwdEnd = cwdStart;
+ if (*cwdEnd) {
+ cwdEnd += strlen(cwdEnd) + 1;
+ while (*cwdEnd) {
+ if (cwdEnd[0] != '=' || cwdEnd[1] == '\0'
+ || cwdEnd[2] != ':' || cwdEnd[3] != '=') {
+ break;
+ }
+ cwdEnd += strlen(cwdEnd) + 1;
+ }
+ }
+ envBlockSize = cwdEnd - cwdStart;
+
+ for (env = envp; *env; env++) {
+ envBlockSize += strlen(*env) + 1;
+ }
+ envBlockSize++;
+
+ p = *envBlock = PR_MALLOC(envBlockSize);
+ if (p == NULL) {
+ return -1;
+ }
+
+ q = cwdStart;
+ while (q < cwdEnd) {
+ *p++ = *q++;
+ }
+
+ for (env = envp; *env; env++) {
+ q = *env;
+ while (*q) {
+ *p++ = *q++;
+ }
+ *p++ = '\0';
+ }
+ *p = '\0';
+ return 0;
+}
+
+/*
+ * For qsort. We sort (case-insensitive) the environment strings
+ * before generating the environment block.
+ */
+static int compare(const void *arg1, const void *arg2)
+{
+ return stricmp(* (char**)arg1, * (char**)arg2);
+}
+PRProcess * _PR_CreateOS2Process(
+ const char *path,
+ char *const *argv,
+ char *const *envp,
+ const PRProcessAttr *attr)
+{
+ char szFailed[CCHMAXPATH];
+ RESULTCODES procInfo;
+ APIRET retVal;
+ char *cmdLine = NULL;
+ char *envBlock = NULL;
+ char **newEnvp;
+ PRProcess *proc = NULL;
+ HFILE hStdIn = 0,
+ hStdOut = 0,
+ hStdErr = 0;
+
+
+ proc = PR_NEW(PRProcess);
+ if (!proc) {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ goto errorExit;
+ }
+
+ if (assembleCmdLine(argv, &cmdLine) == -1) {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ goto errorExit;
+ }
+
+ if (envp == NULL) {
+ newEnvp = NULL;
+ } else {
+ int i;
+ int numEnv = 0;
+ while (envp[numEnv]) {
+ numEnv++;
+ }
+ newEnvp = (char **) PR_MALLOC((numEnv+1) * sizeof(char *));
+ for (i = 0; i <= numEnv; i++) {
+ newEnvp[i] = envp[i];
+ }
+ qsort((void *) newEnvp, (size_t) numEnv, sizeof(char *), compare);
+ }
+ if (assembleEnvBlock(newEnvp, &envBlock) == -1) {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ goto errorExit;
+ }
+
+ if (attr) {
+ PRBool redirected = PR_FALSE;
+
+ /* On OS/2, there is really no way to pass file handles for stdin, stdout,
+ * and stderr to a new process. Instead, we can make it a child process
+ * and make the given file handles a copy of our stdin, stdout, and stderr.
+ * The child process then inherits ours, and we set ours back. Twisted
+ * and gross I know. If you know a better way, please use it.
+ */
+ if (attr->stdinFd) {
+ hStdIn = (HFILE) attr->stdinFd->secret->md.osfd;
+ DosDupHandle(0, &hStdIn);
+ }
+ if (attr->stdoutFd) {
+ hStdOut = (HFILE) attr->stdoutFd->secret->md.osfd;
+ DosDupHandle(1, &hStdOut);
+ }
+ if (attr->stderrFd) {
+ hStdErr = (HFILE) attr->stderrFd->secret->md.osfd;
+ DosDupHandle(2, &hStdErr);
+ }
+ }
+
+ retVal = DosExecPgm(szFailed,
+ CCHMAXPATH,
+ EXEC_ASYNCRESULT,
+ cmdLine,
+ envBlock,
+ &procInfo,
+ argv[0]);
+
+ /* Restore our old values. Hope this works */
+ if(hStdIn){
+ hStdIn = 0;
+ DosDupHandle(0, &hStdIn);
+ }
+ if(hStdOut){
+ hStdOut = 1;
+ DosDupHandle(1, &hStdOut);
+ }
+ if(hStdErr){
+ hStdErr = 1;
+ DosDupHandle(0, &hStdErr);
+ }
+
+ if (retVal != NO_ERROR) {
+ /* XXX what error code? */
+ PR_SetError(PR_UNKNOWN_ERROR, retVal);
+ goto errorExit;
+ }
+
+ proc->md.pid = procInfo.codeTerminate;
+
+ PR_DELETE(cmdLine);
+ if (envBlock) {
+ PR_DELETE(envBlock);
+ }
+ return proc;
+
+errorExit:
+ if (cmdLine) {
+ PR_DELETE(cmdLine);
+ }
+ if (envBlock) {
+ PR_DELETE(envBlock);
+ }
+ if (proc) {
+ PR_DELETE(proc);
+ }
+ return NULL;
+
+} /* _PR_CreateWindowsProcess */
+
+PRStatus _PR_DetachOS2Process(PRProcess *process)
+{
+ /* This is basically what they did on Windows (CloseHandle)
+ * but I don't think it will do much on OS/2. A process is
+ * either created as a child or not. You can't 'detach' it
+ * later on.
+ */
+ DosClose(process->md.pid);
+ PR_DELETE(process);
+ return PR_SUCCESS;
+}
+
+/*
+ * XXX: This will currently only work on a child process.
+ */
+PRStatus _PR_WaitOS2Process(PRProcess *process,
+ PRInt32 *exitCode)
+{
+ ULONG ulRetVal;
+ RESULTCODES results;
+ PID pidEnded = 0;
+
+ ulRetVal = DosWaitChild(DCWA_PROCESS, DCWW_WAIT,
+ &results,
+ &pidEnded, process->md.pid);
+
+ if (ulRetVal != NO_ERROR) {
+ printf("\nDosWaitChild rc = %i\n", ulRetVal);
+ PR_SetError(PR_UNKNOWN_ERROR, ulRetVal);
+ return PR_FAILURE;
+ }
+ PR_DELETE(process);
+ return PR_SUCCESS;
+}
+
+PRStatus _PR_KillOS2Process(PRProcess *process)
+{
+ ULONG ulRetVal;
+ if ((ulRetVal = DosKillProcess(DKP_PROCESS, process->md.pid)) == NO_ERROR) {
+ return PR_SUCCESS;
+ }
+ PR_SetError(PR_UNKNOWN_ERROR, ulRetVal);
+ return PR_FAILURE;
+}
+
+PR_IMPLEMENT(PRStatus) _MD_OS2GetHostName(char *name, PRUint32 namelen)
+{
+ PRIntn rv;
+ PRInt32 syserror;
+
+ rv = gethostname(name, (PRInt32) namelen);
+ if (0 == rv) {
+ return PR_SUCCESS;
+ }
+ _PR_MD_MAP_GETHOSTNAME_ERROR(sock_errno());
+ return PR_FAILURE;
+}
+
+PR_IMPLEMENT(void)
+_PR_MD_WAKEUP_CPUS( void )
+{
+ return;
+}
+
+
+/*
+ **********************************************************************
+ *
+ * Memory-mapped files are not supported on OS/2 (or Win16).
+ *
+ **********************************************************************
+ */
+
+PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size)
+{
+ PR_ASSERT(!"Not implemented");
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+}
+
+void * _MD_MemMap(
+ PRFileMap *fmap,
+ PRInt64 offset,
+ PRUint32 len)
+{
+ PR_ASSERT(!"Not implemented");
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return NULL;
+}
+
+PRStatus _MD_MemUnmap(void *addr, PRUint32 len)
+{
+ PR_ASSERT(!"Not implemented");
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+}
+
+PRStatus _MD_CloseFileMap(PRFileMap *fmap)
+{
+ PR_ASSERT(!"Not implemented");
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+}
+
diff --git a/pr/src/md/os2/os2poll.c b/pr/src/md/os2/os2poll.c
new file mode 100644
index 00000000..b3353aa7
--- /dev/null
+++ b/pr/src/md/os2/os2poll.c
@@ -0,0 +1,165 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+ * This file implements _PR_MD_PR_POLL for OS/2.
+ */
+
+#include "primpl.h"
+
+PRInt32
+_PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds,
+ PRIntervalTime timeout)
+{
+ PRPollDesc *pd, *epd;
+ PRInt32 n, err, pdcnt;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+
+ fd_set rd, wt, ex;
+ struct timeval tv, *tvp = NULL;
+ int maxfd = -1;
+
+ /*
+ * For restarting _MD_SELECT() if it is interrupted by a signal.
+ * We use these variables to figure out how much time has elapsed
+ * and how much of the timeout still remains.
+ */
+ PRIntervalTime start, elapsed, remaining;
+
+ FD_ZERO(&rd);
+ FD_ZERO(&wt);
+ FD_ZERO(&ex);
+
+ for (pd = pds, epd = pd + npds; pd < epd; pd++) {
+ PRInt32 osfd;
+ PRInt16 in_flags = pd->in_flags;
+ PRFileDesc *bottom = pd->fd;
+
+ if ((NULL == bottom) || (in_flags == 0)) {
+ continue;
+ }
+ while (bottom->lower != NULL) {
+ bottom = bottom->lower;
+ }
+ osfd = bottom->secret->md.osfd;
+
+ if (osfd > maxfd) {
+ maxfd = osfd;
+ }
+ if (in_flags & PR_POLL_READ) {
+ FD_SET(osfd, &rd);
+ }
+ if (in_flags & PR_POLL_WRITE) {
+ FD_SET(osfd, &wt);
+ }
+ if (in_flags & PR_POLL_EXCEPT) {
+ FD_SET(osfd, &ex);
+ }
+ }
+ if (timeout != PR_INTERVAL_NO_TIMEOUT) {
+ tv.tv_sec = PR_IntervalToSeconds(timeout);
+ tv.tv_usec = PR_IntervalToMicroseconds(timeout) % PR_USEC_PER_SEC;
+ tvp = &tv;
+ start = PR_IntervalNow();
+ }
+
+retry:
+ n = _MD_SELECT(maxfd + 1, &rd, &wt, &ex, tvp);
+ if (n == -1 && errno == EINTR) {
+ if (timeout == PR_INTERVAL_NO_TIMEOUT) {
+ goto retry;
+ } else {
+ elapsed = (PRIntervalTime) (PR_IntervalNow() - start);
+ if (elapsed > timeout) {
+ n = 0; /* timed out */
+ } else {
+ remaining = timeout - elapsed;
+ tv.tv_sec = PR_IntervalToSeconds(remaining);
+ tv.tv_usec = PR_IntervalToMicroseconds(
+ remaining - PR_SecondsToInterval(tv.tv_sec));
+ goto retry;
+ }
+ }
+ }
+
+ if (n > 0) {
+ n = 0;
+ for (pd = pds, epd = pd + npds; pd < epd; pd++) {
+ PRInt32 osfd;
+ PRInt16 in_flags = pd->in_flags;
+ PRInt16 out_flags = 0;
+ PRFileDesc *bottom = pd->fd;
+
+ if ((NULL == bottom) || (in_flags == 0)) {
+ pd->out_flags = 0;
+ continue;
+ }
+ while (bottom->lower != NULL) {
+ bottom = bottom->lower;
+ }
+ osfd = bottom->secret->md.osfd;
+
+ if ((in_flags & PR_POLL_READ) && FD_ISSET(osfd, &rd)) {
+ out_flags |= PR_POLL_READ;
+ }
+ if ((in_flags & PR_POLL_WRITE) && FD_ISSET(osfd, &wt)) {
+ out_flags |= PR_POLL_WRITE;
+ }
+ if ((in_flags & PR_POLL_EXCEPT) && FD_ISSET(osfd, &ex)) {
+ out_flags |= PR_POLL_EXCEPT;
+ }
+ pd->out_flags = out_flags;
+ if (out_flags) {
+ n++;
+ }
+ }
+ PR_ASSERT(n > 0);
+ } else if (n < 0) {
+ err = _MD_ERRNO();
+ if (err == EBADF) {
+ /* Find the bad fds */
+ n = 0;
+ for (pd = pds, epd = pd + npds; pd < epd; pd++) {
+ int optval;
+ int optlen = sizeof(optval);
+ PRFileDesc *bottom = pd->fd;
+ pd->out_flags = 0;
+ if ((NULL == bottom) || (pd->in_flags == 0)) {
+ continue;
+ }
+ while (bottom->lower != NULL) {
+ bottom = bottom->lower;
+ }
+ if (getsockopt(bottom->secret->md.osfd, SOL_SOCKET,
+ SO_TYPE, (char *) &optval, &optlen) == -1) {
+ PR_ASSERT(_MD_ERRNO() == ENOTSOCK);
+ if (_MD_ERRNO() == ENOTSOCK) {
+ pd->out_flags = PR_POLL_NVAL;
+ n++;
+ }
+ }
+ }
+ PR_ASSERT(n > 0);
+ } else {
+ PR_ASSERT(err != EINTR); /* should have been handled above */
+ _PR_MD_MAP_SELECT_ERROR(err);
+ }
+ }
+ return n;
+ }
+
diff --git a/pr/src/md/os2/os2sem.c b/pr/src/md/os2/os2sem.c
new file mode 100644
index 00000000..684ca945
--- /dev/null
+++ b/pr/src/md/os2/os2sem.c
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+ * OS/2-specific semaphore handling code.
+ *
+ */
+
+#include "primpl.h"
+
+
+PR_IMPLEMENT(void)
+_PR_MD_NEW_SEM(_MDSemaphore *md, PRUintn value)
+{
+ int rv;
+
+ /* Our Sems don't support a value > 1 */
+ PR_ASSERT(value <= 1);
+
+ rv = DosCreateEventSem(NULL, &md->sem, 0, 0);
+ PR_ASSERT(rv == NO_ERROR);
+}
+
+PR_IMPLEMENT(void)
+_PR_MD_DESTROY_SEM(_MDSemaphore *md)
+{
+ int rv;
+ rv = DosCloseEventSem(md->sem);
+ PR_ASSERT(rv == NO_ERROR);
+
+}
+
+PR_IMPLEMENT(PRStatus)
+_PR_MD_TIMED_WAIT_SEM(_MDSemaphore *md, PRIntervalTime ticks)
+{
+ int rv;
+ rv = DosWaitEventSem(md->sem, PR_IntervalToMilliseconds(ticks));
+
+ if (rv == NO_ERROR)
+ return PR_SUCCESS;
+ else
+ return PR_FAILURE;
+}
+
+PR_IMPLEMENT(PRStatus)
+_PR_MD_WAIT_SEM(_MDSemaphore *md)
+{
+ return _PR_MD_TIMED_WAIT_SEM(md, PR_INTERVAL_NO_TIMEOUT);
+}
+
+PR_IMPLEMENT(void)
+_PR_MD_POST_SEM(_MDSemaphore *md)
+{
+ int rv;
+ rv = DosPostEventSem(md->sem);
+ PR_ASSERT(rv == NO_ERROR);
+}
+
+
diff --git a/pr/src/md/os2/os2sock.c b/pr/src/md/os2/os2sock.c
new file mode 100644
index 00000000..3eb26d35
--- /dev/null
+++ b/pr/src/md/os2/os2sock.c
@@ -0,0 +1,770 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/* OS/2 Sockets module
+ *
+ */
+
+/*Note from DSR111297 - it should be noted that there are two flavors of select() on OS/2 */
+/*There is standard BSD (which is kind of slow) and a new flavor of select() that takes */
+/*an integer list of sockets, the number of read sockets, write sockets, except sockets, and */
+/*a millisecond count for timeout. In the interest of performance I have choosen the OS/2 */
+/*specific version of select(). See OS/2 TCP/IP Programmer's Toolkit for more info. */
+
+#include "primpl.h"
+
+void
+_PR_MD_INIT_IO()
+{
+ sock_init();
+}
+
+/* --- SOCKET IO --------------------------------------------------------- */
+
+
+PRInt32
+_PR_MD_SOCKET(int af, int type, int flags)
+{
+ int sock;
+ PRUint32 one = 1;
+ PRInt32 rv;
+ PRInt32 err;
+
+ sock = socket(af, type, flags);
+
+ if (sock == -1 )
+ {
+ int rv = sock_errno();
+ soclose(sock);
+ _PR_MD_MAP_SOCKET_ERROR(rv);
+ return (PRInt32) -1;
+ }
+
+ /*
+ ** Make the socket Non-Blocking
+ */
+ rv = ioctl( sock, FIONBIO, (char *) &one, sizeof(one));
+ if ( rv != 0 )
+ {
+ err = sock_errno();
+ return -1;
+ }
+
+ return (PRInt32)sock;
+}
+
+/*
+** _MD_CloseSocket() -- Close a socket
+**
+*/
+PRInt32
+_MD_CloseSocket(PRInt32 osfd)
+{
+ PRInt32 rv = -1;
+
+ rv = soclose((int) osfd );
+ if (rv < 0)
+ _PR_MD_MAP_SOCKET_ERROR(sock_errno());
+
+ return rv;
+}
+
+PRInt32
+_MD_SocketAvailable(PRFileDesc *fd)
+{
+ PRInt32 result;
+
+ if (ioctl(fd->secret->md.osfd, FIONREAD, (char *) &result, sizeof(result)) < 0) {
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, sock_errno());
+ return -1;
+ }
+ return result;
+}
+
+PRInt32
+_MD_Accept(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen,
+ PRIntervalTime timeout )
+{
+ PRInt32 osfd = fd->secret->md.osfd;
+ PRInt32 rv, err;
+#ifdef BSD_SELECT
+ fd_set rd;
+ struct timeval tv, *tvp;
+
+ FD_ZERO(&rd);
+ FD_SET(osfd, &rd);
+#else
+ int socks[1];
+ socks[0] = osfd;
+#endif
+ if (timeout == PR_INTERVAL_NO_TIMEOUT)
+ {
+ while ((rv = accept(osfd, (struct sockaddr *) raddr, (int *) rlen)) == -1)
+ {
+ if (((err = sock_errno()) == EWOULDBLOCK)
+ && (!fd->secret->nonblocking))
+ {
+#ifdef BSD_SELECT
+ if ((rv = select(osfd + 1, &rd, NULL, NULL,NULL)) == -1) {
+#else
+ if ((rv = select(socks, 1, 0, 0, -1)) == -1) {
+#endif
+ _PR_MD_MAP_SELECT_ERROR(sock_errno());
+ break;
+ }
+ }
+ else {
+ _PR_MD_MAP_ACCEPT_ERROR(err);
+ break;
+ }
+ }
+ return(rv);
+ }
+ else if (timeout == PR_INTERVAL_NO_WAIT)
+ {
+ if ((rv = accept(osfd, (struct sockaddr *) raddr, (int *) rlen)) == -1)
+ {
+ if (((err = sock_errno()) == EWOULDBLOCK)
+ && (!fd->secret->nonblocking))
+ {
+ PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+ }
+ else
+ {
+ _PR_MD_MAP_ACCEPT_ERROR(err);
+ }
+ }
+ return(rv);
+ }
+ else
+ {
+retry:
+ if ((rv = accept(osfd, (struct sockaddr *) raddr, (int *) rlen)) == -1)
+ {
+ if (((err = sock_errno()) == EWOULDBLOCK)
+ && (!fd->secret->nonblocking))
+ {
+#ifdef BSD_SELECT
+ tv.tv_sec = PR_IntervalToSeconds(timeout);
+ tv.tv_usec = PR_IntervalToMicroseconds(
+ timeout - PR_SecondsToInterval(tv.tv_sec));
+ tvp = &tv;
+ rv = select(osfd + 1, &rd, NULL, NULL, tvp);
+#else
+ long lTimeout = PR_IntervalToMilliseconds(timeout);
+ rv = select(socks, 1, 0, 0, lTimeout);
+#endif
+ if (rv > 0) {
+ goto retry;
+ }
+ else if (rv == 0)
+ {
+ PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+ rv = -1;
+ } else {
+ _PR_MD_MAP_SELECT_ERROR(sock_errno());
+ }
+ } else {
+ _PR_MD_MAP_ACCEPT_ERROR(err);
+ }
+ }
+ }
+ return(rv);
+} /* end _MD_Accept() */
+
+
+
+PRInt32
+_PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen,
+ PRIntervalTime timeout)
+{
+ PRInt32 osfd = fd->secret->md.osfd;
+ PRInt32 rv;
+ int err, len;
+#ifdef BSD_SELECT
+ fd_set wd, ex;
+ struct timeval tv, *tvp;
+#else
+ int socks[1];
+ long lTimeout = -1;
+#endif
+
+ if ((rv = connect(osfd, (struct sockaddr *) addr, addrlen)) == -1)
+ {
+ err = sock_errno();
+ if ((!fd->secret->nonblocking) && (err == EINPROGRESS) || (err == EWOULDBLOCK))
+ {
+#ifdef BSD_SELECT
+ if (timeout == PR_INTERVAL_NO_TIMEOUT)
+ tvp = NULL;
+ else
+ {
+ tv.tv_sec = PR_IntervalToSeconds(timeout);
+ tv.tv_usec = PR_IntervalToMicroseconds(
+ timeout - PR_SecondsToInterval(tv.tv_sec));
+ tvp = &tv;
+ }
+
+ FD_ZERO(&wd);
+ FD_SET(osfd, &wd);
+ FD_ZERO(&ex);
+ FD_SET(osfd, &ex);
+ rv = select(osfd + 1, NULL, &wd, &ex, tvp);
+#else
+ if (timeout == PR_INTERVAL_NO_TIMEOUT)
+ lTimeout = -1;
+ else
+ {
+ lTimeout = PR_IntervalToMilliseconds(timeout);
+ }
+
+ socks[0] = osfd;
+ rv = select(socks, 0, 1, 1, lTimeout);
+#endif
+ if (rv > 0)
+ {
+#ifdef BSD_SELECT
+ if (FD_ISSET(osfd, &ex))
+ {
+ DosSleep(0);
+ len = sizeof(err);
+ if (getsockopt(osfd, SOL_SOCKET, SO_ERROR,
+ (char *) &err, &len) < 0)
+ {
+ _PR_MD_MAP_GETSOCKOPT_ERROR(sock_errno());
+ return -1;
+ }
+ if (err != 0)
+ _PR_MD_MAP_CONNECT_ERROR(err);
+ else
+ PR_SetError(PR_UNKNOWN_ERROR, 0);
+ return -1;
+ }
+ if (FD_ISSET(osfd, &wd))
+ {
+ /* it's connected */
+ return 0;
+ }
+#else
+ if (getsockopt(osfd, SOL_SOCKET, SO_ERROR,
+ (char *) &err, &len) < 0)
+ {
+ _PR_MD_MAP_GETSOCKOPT_ERROR(sock_errno());
+ return -1;
+ }
+ else
+ return 0; /* It's connected ! */
+#endif
+ }
+ else if (rv == 0)
+ {
+ PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+ return(-1);
+ } else if (rv < 0)
+ {
+ _PR_MD_MAP_SELECT_ERROR(sock_errno());
+ return(-1);
+ }
+ }
+ _PR_MD_MAP_CONNECT_ERROR(err);
+ }
+ return rv;
+}
+
+
+PRInt32
+_PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen)
+{
+ PRInt32 rv;
+ int one = 1;
+
+ rv = bind(fd->secret->md.osfd, (struct sockaddr*) &(addr->inet), addrlen);
+
+ if (rv == -1) {
+ _PR_MD_MAP_BIND_ERROR(sock_errno());
+ return -1;
+ }
+
+ return 0;
+}
+
+
+PRInt32
+_PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
+ PRIntervalTime timeout)
+{
+ PRInt32 osfd = fd->secret->md.osfd;
+ PRInt32 rv, err;
+#ifdef BSD_SELECT
+ struct timeval tv, *tvp;
+ fd_set rd;
+#else
+ int socks[1];
+ long lTimeout = -1;
+#endif
+
+ while ((rv = recv( osfd, buf, amount, 0)) == -1)
+ {
+ if (((err = sock_errno()) == EWOULDBLOCK)
+ && (!fd->secret->nonblocking))
+ {
+#ifdef BSD_SELECT
+ FD_ZERO(&rd);
+ FD_SET(osfd, &rd);
+ if (timeout == PR_INTERVAL_NO_TIMEOUT)
+ {
+ tvp = NULL;
+ }
+ else
+ {
+ tv.tv_sec = PR_IntervalToSeconds(timeout);
+ tv.tv_usec = PR_IntervalToMicroseconds(
+ timeout - PR_SecondsToInterval(tv.tv_sec));
+ tvp = &tv;
+ }
+ if ((rv = select(osfd + 1, &rd, NULL, NULL, tvp)) == -1)
+#else
+ socks[0] = osfd;
+ if (timeout == PR_INTERVAL_NO_TIMEOUT)
+ {
+ lTimeout = -1;
+ }
+ else
+ {
+ lTimeout = PR_IntervalToMilliseconds(timeout);
+ }
+ if ((rv = select(socks, 1, 0, 0, lTimeout)) == -1)
+#endif
+ {
+ _PR_MD_MAP_SELECT_ERROR(sock_errno());
+ return -1;
+ }
+ else if (rv == 0)
+ {
+ PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+ rv = -1;
+ break;
+ }
+ }
+ else
+ {
+ _PR_MD_MAP_RECV_ERROR(err);
+ break;
+ }
+ } /* end while() */
+ return(rv);
+}
+
+PRInt32
+_PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
+ PRIntervalTime timeout)
+{
+ PRInt32 osfd = fd->secret->md.osfd;
+ PRInt32 rv, err;
+#ifdef BSD_SELECT
+ struct timeval tv, *tvp;
+ fd_set wd;
+#else
+ int socks[1];
+ long lTimeout = -1;
+#endif
+ PRInt32 bytesSent = 0;
+
+ while(bytesSent < amount )
+ {
+ while ((rv = send( osfd, (char *) buf, amount, 0 )) == -1)
+ {
+ if (((err = sock_errno()) == EWOULDBLOCK)
+ && (!fd->secret->nonblocking))
+ {
+#ifdef BSD_SELECT
+ if ( timeout == PR_INTERVAL_NO_TIMEOUT )
+ {
+ tvp = NULL;
+ }
+ else
+ {
+ tv.tv_sec = PR_IntervalToSeconds(timeout);
+ tv.tv_usec = PR_IntervalToMicroseconds(
+ timeout - PR_SecondsToInterval(tv.tv_sec));
+ tvp = &tv;
+ }
+ FD_ZERO(&wd);
+ FD_SET(osfd, &wd);
+ if ((rv = select( osfd + 1, NULL, &wd, NULL,tvp)) == -1) {
+#else
+ if ( timeout == PR_INTERVAL_NO_TIMEOUT )
+ {
+ lTimeout = -1;
+ }
+ else
+ {
+ lTimeout = PR_IntervalToMilliseconds(timeout);
+ }
+ socks[0] = osfd;
+ if ((rv = select( socks, 0, 1, 0, lTimeout)) == -1) {
+#endif
+ _PR_MD_MAP_SELECT_ERROR(sock_errno());
+ break;
+ }
+ if (rv == 0)
+ {
+ PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+ return -1;
+ }
+ }
+ else {
+ _PR_MD_MAP_SEND_ERROR(err);
+ return -1;
+ }
+ }
+ bytesSent += rv;
+ if (fd->secret->nonblocking)
+ {
+ break;
+ }
+ if ((rv >= 0) && (bytesSent < amount ))
+ {
+#ifdef BSD_SELECT
+ if ( timeout == PR_INTERVAL_NO_TIMEOUT )
+ {
+ tvp = NULL;
+ }
+ else
+ {
+ tv.tv_sec = PR_IntervalToSeconds(timeout);
+ tv.tv_usec = PR_IntervalToMicroseconds(
+ timeout - PR_SecondsToInterval(tv.tv_sec));
+ tvp = &tv;
+ }
+ FD_ZERO(&wd);
+ FD_SET(osfd, &wd);
+ if ((rv = select(osfd + 1, NULL, &wd, NULL,tvp)) == -1) {
+#else
+ if ( timeout == PR_INTERVAL_NO_TIMEOUT )
+ {
+ lTimeout = -1;
+ }
+ else
+ {
+ lTimeout = PR_IntervalToMilliseconds(timeout);
+ }
+ socks[0] = osfd;
+ if ((rv = select(socks, 0, 1, 0,lTimeout)) == -1) {
+#endif
+ _PR_MD_MAP_SELECT_ERROR(sock_errno());
+ break;
+ }
+ if (rv == 0)
+ {
+ PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+ return -1;
+ }
+ }
+ }
+ return bytesSent;
+}
+
+PRInt32
+_PR_MD_SENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
+ const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
+{
+ PRInt32 osfd = fd->secret->md.osfd;
+ PRInt32 rv, err;
+ PRInt32 bytesSent = 0;
+#ifdef BSD_SELECT
+ struct timeval tv, *tvp;
+ fd_set wd;
+#else
+ int socks[1];
+ long lTimeout = -1;
+#endif
+
+ while(bytesSent < amount)
+ {
+ while ((rv = sendto( osfd, (char *) buf, amount, 0, (struct sockaddr *) addr,
+ addrlen)) == -1)
+ {
+ if (((err = sock_errno()) == EWOULDBLOCK)
+ && (!fd->secret->nonblocking))
+ {
+#ifdef BSD_SELECT
+ if ( timeout == PR_INTERVAL_NO_TIMEOUT )
+ {
+ tvp = NULL;
+ }
+ else
+ {
+ tv.tv_sec = PR_IntervalToSeconds(timeout);
+ tv.tv_usec = PR_IntervalToMicroseconds(
+ timeout - PR_SecondsToInterval(tv.tv_sec));
+ tvp = &tv;
+ }
+ FD_ZERO(&wd);
+ FD_SET(osfd, &wd);
+ if ((rv = select(osfd + 1, NULL, &wd, NULL, tvp)) == -1) {
+#else
+ if ( timeout == PR_INTERVAL_NO_TIMEOUT )
+ {
+ lTimeout = -1;
+ }
+ else
+ {
+ lTimeout = PR_IntervalToMilliseconds(timeout);
+ }
+ socks[0] = osfd;
+ if ((rv = select(socks, 0, 1, 0, lTimeout)) == -1) {
+#endif
+ _PR_MD_MAP_SELECT_ERROR(sock_errno());
+ break;
+ }
+ if (rv == 0)
+ {
+ PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+ return -1;
+ }
+ }
+ else {
+ _PR_MD_MAP_SENDTO_ERROR(err);
+ return -1;
+ }
+ }
+ bytesSent += rv;
+ if (fd->secret->nonblocking)
+ {
+ break;
+ }
+ if ((rv >= 0) && (bytesSent < amount ))
+ {
+#ifdef BSD_SELECT
+ if ( timeout == PR_INTERVAL_NO_TIMEOUT )
+ {
+ tvp = NULL;
+ }
+ else
+ {
+ tv.tv_sec = PR_IntervalToSeconds(timeout);
+ tv.tv_usec = PR_IntervalToMicroseconds(
+ timeout - PR_SecondsToInterval(tv.tv_sec));
+ tvp = &tv;
+ }
+ FD_ZERO(&wd);
+ FD_SET(osfd, &wd);
+ if ((rv = select( osfd + 1, NULL, &wd, NULL, tvp)) == -1) {
+#else
+ if ( timeout == PR_INTERVAL_NO_TIMEOUT )
+ {
+ lTimeout = -1;
+ }
+ else
+ {
+ lTimeout = PR_IntervalToMilliseconds(timeout);
+ }
+ socks[0] = osfd;
+ if ((rv = select( socks, 0, 1, 0, lTimeout)) == -1) {
+#endif
+ _PR_MD_MAP_SELECT_ERROR(sock_errno());
+ break;
+ }
+ if (rv == 0)
+ {
+ PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+ return -1;
+ }
+ }
+ }
+ return bytesSent;
+}
+
+PRInt32
+_PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
+ PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
+{
+ PRInt32 osfd = fd->secret->md.osfd;
+ PRInt32 rv, err;
+ PRUint32 addrlen_temp = *addrlen;
+#ifdef BSD_SELECT
+ struct timeval tv, *tvp;
+ fd_set rd;
+#else
+ int socks[1];
+ long lTimeout = -1;
+#endif
+
+ while ((rv = recvfrom( osfd, (char *) buf, amount, 0, (struct sockaddr *) addr,
+ (int *) addrlen)) == -1)
+ {
+ if (((err = sock_errno()) == EWOULDBLOCK)
+ && (!fd->secret->nonblocking))
+ {
+#ifdef BSD_SELECT
+ if (timeout == PR_INTERVAL_NO_TIMEOUT)
+ {
+ tvp = NULL;
+ }
+ else
+ {
+ tv.tv_sec = PR_IntervalToSeconds(timeout);
+ tv.tv_usec = PR_IntervalToMicroseconds(
+ timeout - PR_SecondsToInterval(tv.tv_sec));
+ tvp = &tv;
+ }
+ FD_ZERO(&rd);
+ FD_SET(osfd, &rd);
+ if ((rv = select(osfd + 1, &rd, NULL, NULL, tvp)) == -1)
+#else
+ if (timeout == PR_INTERVAL_NO_TIMEOUT)
+ {
+ lTimeout = -1;
+ }
+ else
+ {
+ lTimeout = PR_IntervalToMilliseconds(timeout);
+ }
+ socks[0] = osfd;
+ if ((rv = select(socks, 1, 0, 0, lTimeout)) == -1)
+#endif
+ {
+ _PR_MD_MAP_SELECT_ERROR(sock_errno());
+ return -1;
+ } else if (rv == 0)
+ {
+ PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+ rv = -1;
+ break;
+ }
+
+ /* recvfrom blows this value away if it fails first time */
+ *addrlen = addrlen_temp;
+ }
+ else
+ {
+ _PR_MD_MAP_RECVFROM_ERROR(err);
+ break;
+ }
+ }
+ return(rv);
+}
+
+PRInt32
+_PR_MD_WRITEV(PRFileDesc *fd, PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout)
+{
+ int index;
+ int sent = 0;
+ int rv;
+
+ for (index=0; index < iov_size; index++)
+ {
+ rv = _PR_MD_SEND(fd, iov[index].iov_base, iov[index].iov_len, 0, timeout);
+ if (rv > 0)
+ sent += rv;
+ if ( rv != iov[index].iov_len )
+ {
+ if (rv < 0)
+ {
+ if (fd->secret->nonblocking
+ && (PR_GetError() == PR_WOULD_BLOCK_ERROR)
+ && (sent > 0))
+ {
+ return sent;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ /* Only a nonblocking socket can have partial sends */
+ PR_ASSERT(fd->secret->nonblocking);
+ return sent;
+ }
+ }
+ return sent;
+}
+
+PRInt32
+_PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how)
+{
+PRInt32 rv;
+
+ rv = shutdown(fd->secret->md.osfd, how);
+ if (rv < 0)
+ _PR_MD_MAP_SHUTDOWN_ERROR(sock_errno());
+ return rv;
+}
+
+PRStatus
+_PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len)
+{
+ PRInt32 rv;
+
+ rv = getsockname((int)fd->secret->md.osfd, (struct sockaddr *)addr, (int *) len);
+ if (rv==0)
+ return PR_SUCCESS;
+ else {
+ _PR_MD_MAP_GETSOCKNAME_ERROR(sock_errno());
+ return PR_FAILURE;
+ }
+}
+
+PRStatus
+_PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len)
+{
+ PRInt32 rv;
+
+ rv = getpeername((int)fd->secret->md.osfd, (struct sockaddr *)addr, (int *) len);
+ if (rv==0)
+ return PR_SUCCESS;
+ else {
+ _PR_MD_MAP_GETPEERNAME_ERROR(sock_errno());
+ return PR_FAILURE;
+ }
+}
+
+PRStatus
+_PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen)
+{
+ PRInt32 rv;
+
+ rv = getsockopt((int)fd->secret->md.osfd, level, optname, optval, optlen);
+ if (rv==0)
+ return PR_SUCCESS;
+ else {
+ _PR_MD_MAP_GETSOCKOPT_ERROR(sock_errno());
+ return PR_FAILURE;
+ }
+}
+
+PRStatus
+_PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen)
+{
+ PRInt32 rv;
+
+ rv = setsockopt((int)fd->secret->md.osfd, level, optname, (char *) optval, optlen);
+ if (rv==0)
+ return PR_SUCCESS;
+ else {
+ _PR_MD_MAP_SETSOCKOPT_ERROR(sock_errno());
+ return PR_FAILURE;
+ }
+}
+
+void
+_MD_MakeNonblock(PRFileDesc *f)
+{
+ return; /* do nothing! */
+}
diff --git a/pr/src/md/os2/os2thred.c b/pr/src/md/os2/os2thred.c
new file mode 100644
index 00000000..e51b3eb3
--- /dev/null
+++ b/pr/src/md/os2/os2thred.c
@@ -0,0 +1,245 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+#include "primpl.h"
+#include <process.h> /* for _beginthread() */
+
+APIRET (* APIENTRY QueryThreadContext)(TID, ULONG, PCONTEXTRECORD);
+
+/* --- globals ------------------------------------------------ */
+_NSPR_TLS* pThreadLocalStorage = 0;
+_PRInterruptTable _pr_interruptTable[] = { { 0 } };
+
+PR_IMPLEMENT(void)
+_PR_MD_ENSURE_TLS()
+{
+ if(!pThreadLocalStorage)
+ {
+ /* Allocate thread local storage (TLS). Note, that only 32 bytes can
+ * be allocated at a time.
+ */
+ int rc = DosAllocThreadLocalMemory(sizeof(_NSPR_TLS) / 4, (PULONG*)&pThreadLocalStorage);
+ PR_ASSERT(rc == NO_ERROR);
+ memset(pThreadLocalStorage, 0, sizeof(_NSPR_TLS));
+ }
+}
+
+PR_IMPLEMENT(void)
+_PR_MD_EARLY_INIT()
+{
+ HMODULE hmod;
+
+ if (DosLoadModule(NULL, 0, "DOSCALL1.DLL", &hmod) == 0)
+ DosQueryProcAddr(hmod, 877, "DOSQUERYTHREADCONTEXT",
+ (PFN *)&QueryThreadContext);
+}
+
+PR_IMPLEMENT(void)
+_PR_MD_INIT_PRIMORDIAL_THREAD(PRThread *thread)
+{
+ PTIB ptib;
+ PPIB ppib;
+ PRUword rc;
+
+ rc = DosGetInfoBlocks(&ptib, &ppib);
+
+ thread->md.handle = ptib->tib_ptib2->tib2_ultid;
+}
+
+
+PR_IMPLEMENT(PRStatus)
+_PR_MD_INIT_THREAD(PRThread *thread)
+{
+ APIRET rc;
+
+ if (thread->flags & _PR_PRIMORDIAL)
+ _PR_MD_INIT_PRIMORDIAL_THREAD(thread);
+
+ /* Create the blocking IO semaphore */
+ _PR_MD_NEW_SEM(&thread->md.blocked_sema, 1);
+ return (thread->md.blocked_sema.sem != NULL) ? PR_SUCCESS : PR_FAILURE;
+}
+
+PR_IMPLEMENT(PRStatus)
+_PR_MD_CREATE_THREAD(PRThread *thread,
+ void (*start)(void *),
+ PRThreadPriority priority,
+ PRThreadScope scope,
+ PRThreadState state,
+ PRUint32 stackSize)
+{
+ thread->md.handle = thread->id = (TID) _beginthread(
+ (void(* _Optlink)(void*))start,
+ NULL,
+ thread->stack->stackSize,
+ thread);
+ if(thread->md.handle == -1) {
+ return PR_FAILURE;
+ }
+ _PR_MD_SET_PRIORITY(&(thread->md), priority);
+
+ return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(void)
+_PR_MD_YIELD(void)
+{
+ /* Isn't there some problem with DosSleep(0) on OS/2? */
+ DosSleep(0);
+}
+
+PR_IMPLEMENT(void)
+_PR_MD_SET_PRIORITY(_MDThread *thread, PRThreadPriority newPri)
+{
+ int nativePri;
+ BOOL rv;
+
+ if (newPri < PR_PRIORITY_FIRST) {
+ newPri = PR_PRIORITY_FIRST;
+ } else if (newPri > PR_PRIORITY_LAST) {
+ newPri = PR_PRIORITY_LAST;
+ }
+ switch (newPri) {
+ case PR_PRIORITY_LOW:
+ nativePri = PRTYC_IDLETIME;
+ break;
+ case PR_PRIORITY_NORMAL:
+ nativePri = PRTYC_REGULAR;
+ break;
+ case PR_PRIORITY_HIGH:
+ nativePri = PRTYC_FOREGROUNDSERVER;
+ break;
+ case PR_PRIORITY_URGENT:
+ nativePri = PRTYC_TIMECRITICAL;
+ }
+ rv = DosSetPriority(PRTYS_THREAD, nativePri, 0, thread->handle);
+ PR_ASSERT(rv == NO_ERROR);
+ if (rv != NO_ERROR) {
+ PR_LOG(_pr_thread_lm, PR_LOG_MIN,
+ ("PR_SetThreadPriority: can't set thread priority\n"));
+ }
+ return;
+}
+
+PR_IMPLEMENT(void)
+_PR_MD_CLEAN_THREAD(PRThread *thread)
+{
+ /* Just call _PR_MD_EXIT_THREAD for now */
+ _PR_MD_EXIT_THREAD(thread);
+}
+
+PR_IMPLEMENT(void)
+_PR_MD_EXIT_THREAD(PRThread *thread)
+{
+ _PR_MD_DESTROY_SEM(&thread->md.blocked_sema);
+
+ if (thread->md.handle) {
+ /* DosKillThread will not kill a suspended thread, but it will mark it
+ * for death; we must resume it after killing it to make sure it knows
+ * it is about to die (pretty wicked, huh?).
+ *
+ * DosKillThread will not kill the current thread, instead we must use
+ * DosExit.
+ */
+ if ( thread != _MD_CURRENT_THREAD() ) {
+ DosKillThread( thread->md.handle );
+ DosResumeThread( thread->md.handle );
+ } else {
+ _endthread();
+ }
+ thread->md.handle = 0;
+ }
+
+ _PR_MD_SET_CURRENT_THREAD(NULL);
+}
+
+
+PR_IMPLEMENT(void)
+_PR_MD_EXIT(PRIntn status)
+{
+ _exit(status);
+}
+
+#ifdef HAVE_THREAD_AFFINITY
+PR_EXTERN(PRInt32)
+_PR_MD_SETTHREADAFFINITYMASK(PRThread *thread, PRUint32 mask )
+{
+ /* Can we do this on OS/2? Only on SMP versions? */
+ PR_ASSERT(!"Not implemented");
+ return 0;
+
+ /* This is what windows does:
+ int rv;
+
+ rv = SetThreadAffinityMask(thread->md.handle, mask);
+
+ return rv?0:-1;
+ */
+}
+
+PR_EXTERN(PRInt32)
+_PR_MD_GETTHREADAFFINITYMASK(PRThread *thread, PRUint32 *mask)
+{
+ /* Can we do this on OS/2? Only on SMP versions? */
+ PR_ASSERT(!"Not implemented");
+ return 0;
+
+ /* This is what windows does:
+ PRInt32 rv, system_mask;
+
+ rv = GetProcessAffinityMask(GetCurrentProcess(), mask, &system_mask);
+
+ return rv?0:-1;
+ */
+}
+#endif /* HAVE_THREAD_AFFINITY */
+
+PR_IMPLEMENT(void)
+_PR_MD_SUSPEND_CPU(_PRCPU *cpu)
+{
+ _PR_MD_SUSPEND_THREAD(cpu->thread);
+}
+
+PR_IMPLEMENT(void)
+_PR_MD_RESUME_CPU(_PRCPU *cpu)
+{
+ _PR_MD_RESUME_THREAD(cpu->thread);
+}
+
+PR_IMPLEMENT(void)
+_PR_MD_SUSPEND_THREAD(PRThread *thread)
+{
+ if (_PR_IS_NATIVE_THREAD(thread)) {
+ APIRET rc;
+
+ /* XXXMB - DosSuspendThread() is not a blocking call; how do we
+ * know when the thread is *REALLY* suspended?
+ */
+ rc = DosSuspendThread(thread->md.handle);
+ PR_ASSERT(rc == NO_ERROR);
+ }
+}
+
+PR_IMPLEMENT(void)
+_PR_MD_RESUME_THREAD(PRThread *thread)
+{
+ if (_PR_IS_NATIVE_THREAD(thread)) {
+ DosResumeThread(thread->md.handle);
+ }
+}
+