--- ./pp_sys.c-pre	Tue Apr  1 13:13:58 2003
+++ ./pp_sys.c	Mon May 26 16:21:14 2003
@@ -4129,14 +4129,14 @@ PP(pp_system)
     result = 0;
     if (PL_op->op_flags & OPf_STACKED) {
 	SV *really = *++MARK;
-#  ifdef WIN32
+#  if defined(WIN32) || defined(OS2)
 	value = (I32)do_aspawn(really, MARK, SP);
 #  else
 	value = (I32)do_aspawn(really, (void **)MARK, (void **)SP);
 #  endif
     }
     else if (SP - MARK != 1) {
-#  ifdef WIN32
+#  if defined(WIN32) || defined(OS2)
 	value = (I32)do_aspawn(Nullsv, MARK, SP);
 #  else
 	value = (I32)do_aspawn(Nullsv, (void **)MARK, (void **)SP);
--- ./os2/OS2/REXX/t/rx_emxrv.t-pre	Fri Jul 19 16:50:02 2002
+++ ./os2/OS2/REXX/t/rx_emxrv.t	Mon May 26 14:07:06 2003
@@ -8,7 +8,7 @@ BEGIN {
     }
 }
 
-print "1..5\n";
+print "1..20\n";
 
 require OS2::DLL;
 print "ok 1\n";
@@ -22,3 +22,40 @@ print "ok 4\n";
 $reason = '';
 $emx_version >= 99 and $reason = ' # skipped: version of EMX 100 or more';	# Be safe
 print "ok 5$reason\n";
+
+$emx_fullname = OS2::DLLname 0x202, $emx_dll->{Handle};	# Handle ==> fullname
+print "ok 6\n";
+$emx_dll1 = OS2::DLL->module($emx_fullname);
+print "ok 7\n";
+$emx_dll->{Handle} == $emx_dll1->{Handle} or print "not ";
+print "ok 8\n";
+
+$emx_version1 = $emx_dll1->emx_revision();
+print "ok 9\n";
+$emx_version1 eq $emx_version or print "not ";
+print "ok 10\n";
+
+$emx_revision = $emx_dll->wrapper_REXX('emx_revision');
+print "ok 11\n";
+$emx_version2 = $emx_revision->();
+print "ok 12\n";
+$emx_version2 eq $emx_version or print "not ";
+print "ok 13\n";
+
+$emx_revision1 = $emx_dll1->wrapper_REXX('#128');
+print "ok 14\n";
+$emx_version3 = $emx_revision1->();
+print "ok 15\n";
+$emx_version3 eq $emx_version or print "not ";
+print "ok 16\n";
+
+($emx_fullname1 = $emx_fullname) =~ s,/,\\,g;
+$emx_dll2 = OS2::DLL->new($emx_fullname1);
+print "ok 17\n";
+$emx_dll->{Handle} == $emx_dll2->{Handle} or print "not ";
+print "ok 18\n";
+
+$emx_version4 = $emx_dll2->emx_revision();
+print "ok 19\n";
+$emx_version4 eq $emx_version or print "not ";
+print "ok 20\n";
--- ./os2/OS2/REXX/t/rx_objcall.t-pre	Fri Jul 19 16:50:02 2002
+++ ./os2/OS2/REXX/t/rx_objcall.t	Mon May 26 17:45:58 2003
@@ -30,4 +30,5 @@ print "ok 4\n" if $res[0] == $$;
 print "# @pid\n";
 
 eval { $rxu->nixda(); };
-print "ok 5\n" if $@ =~ /^Can't find entry 'nixda\'/;
+print "# \$\@ = '$@'\n" if $@;
+print "ok 5\n" if $@ =~ /^Can't find symbol `nixda\'/;
--- ./os2/OS2/REXX/DLL/DLL.pm-pre	Fri Jul 19 16:50:02 2002
+++ ./os2/OS2/REXX/DLL/DLL.pm	Mon May 26 14:07:54 2003
@@ -3,18 +3,7 @@ package OS2::DLL;
 our $VERSION = '1.00';
 
 use Carp;
-use DynaLoader;
-
-@ISA = qw(DynaLoader);
-
-sub AUTOLOAD {
-    $AUTOLOAD =~ /^OS2::DLL::.+::(.+)$/
-      or confess("Undefined subroutine &$AUTOLOAD called");
-    return undef if $1 eq "DESTROY";
-    $_[0]->find($1)
-      or confess("Can't find entry '$1' to DLL '$_[0]->{File}': $^E");
-    goto &$AUTOLOAD;
-}
+use XSLoader;
 
 @libs = split(/;/, $ENV{'PERL5REXX'} || $ENV{'PERLREXX'} || $ENV{'LIBPATH'} || $ENV{'PATH'});
 %dlls = ();
@@ -22,23 +11,10 @@ sub AUTOLOAD {
 # Preloaded methods go here.  Autoload methods go after __END__, and are
 # processed by the autosplit program.
 
-# Cannot autoload, the autoloader is used for the REXX functions.
-
-sub new {
-  confess 'Usage: OS2::DLL->new( <file> [<dirs>] )' unless @_ >= 2;
-  my ($class, $file) = (shift, shift);
-  my $handle;
-  $handle = $class->load($file, @_) and return $handle;
-  my $path = @_ ? " from '@_'" : '';
-  my $err = DynaLoader::dl_error();
-  $err =~ s/\s+at\s+\S+\s+line\s+\S+\s*\z//;
-  croak "Can't load '$file'$path: $err";
-}
+# Cannot be autoload, the autoloader is used for the REXX functions.
 
-sub load
-{
-	confess 'Usage: load OS2::DLL <file> [<dirs>]' unless $#_ >= 1;
-	my ($class, $file, @where) = (@_, @libs);
+my $load_with_dirs = sub {
+	my ($class, $file, @where) = (@_);
 	return $dlls{$file} if $dlls{$file};
 	my $handle;
 	foreach (@where) {
@@ -47,46 +23,86 @@ sub load
 	}
 	$handle = DynaLoader::dl_load_file($file) unless $handle;
 	return undef unless $handle;
-	my $packs = $INC{'OS2/REXX.pm'} ? 'OS2::DLL OS2::REXX' : 'OS2::DLL';
-	eval <<EOE or die "eval package $@";
-package OS2::DLL::$file; \@ISA = qw($packs);
-sub AUTOLOAD {
-  \$OS2::DLL::AUTOLOAD = \$AUTOLOAD;
-  goto &OS2::DLL::AUTOLOAD;
-}
-1;
-EOE
+	my @packs = $INC{'OS2/REXX.pm'} ? qw(OS2::DLL::dll OS2::REXX) : 'OS2::DLL::dll';
+	my $p = "OS2::DLL::dll::$file";
+	@{"$p\::ISA"} = @packs;
+	*{"$p\::AUTOLOAD"} = \&OS2::DLL::dll::AUTOLOAD;
 	return $dlls{$file} = 
-	  bless {Handle => $handle, File => $file, Queue => 'SESSION' },
-		"OS2::DLL::$file";
+	  bless {Handle => $handle, File => $file, Queue => 'SESSION' }, $p;
+};
+
+my $new_dll = sub {
+  my ($dirs, $class, $file) = (shift, shift, shift);
+  my $handle;
+  push @_, @libs if $dirs;
+  $handle = $load_with_dirs->($class, $file, @_)
+    and return $handle;
+  my $path = @_ ? " from '@_'" : '';
+  my $err = DynaLoader::dl_error();
+  $err =~ s/\s+at\s+\S+\s+line\s+\S+\s*\z//;
+  croak "Can't load '$file'$path: $err";
+};
+
+sub new {
+  confess 'Usage: OS2::DLL->new( <file> [<dirs>] )' unless @_ >= 2;
+  $new_dll->(1, @_);
 }
 
-sub find
-{
+sub module {
+  confess 'Usage: OS2::DLL->module( <file> [<dirs>] )' unless @_ >= 2;
+  $new_dll->(0, @_);
+}
+
+sub load {
+  confess 'Usage: load OS2::DLL <file> [<dirs>]' unless $#_ >= 1;
+  $load_with_dirs->(@_, @libs);
+}
+
+package OS2::DLL::dll;
+use Carp;
+@ISA = 'OS2::DLL';
+
+sub AUTOLOAD {
+    $AUTOLOAD =~ /^OS2::DLL::dll::.+::(.+)$/
+      or confess("Undefined subroutine &$AUTOLOAD called");
+    return undef if $1 eq "DESTROY";
+    die "AUTOLOAD loop" if $1 eq "AUTOLOAD";
+    $_[0]->find($1) or confess($@);
+    goto &$AUTOLOAD;
+}
+
+sub wrapper_REXX {
+	confess 'Usage: $dllhandle->wrapper_REXX($func_name)' unless @_ == 2;
 	my $self   = shift;
 	my $file   = $self->{File};
 	my $handle = $self->{Handle};
 	my $prefix = exists($self->{Prefix}) ? $self->{Prefix} : "";
 	my $queue  = $self->{Queue};
-	foreach (@_) {
-		my $name = "OS2::DLL::${file}::$_";
-		next if defined(&$name);
-		my $addr = DynaLoader::dl_find_symbol($handle, uc $prefix.$_)
-		        || DynaLoader::dl_find_symbol($handle, $prefix.$_)
-			or return 0;
-		eval <<EOE or die "eval sub";
-package OS2::DLL::$file;
-sub $_ {
-  shift;
-  OS2::DLL::_call('$_', $addr, '$queue', \@_);
+	my $name = shift;
+	$prefix = '' if $name =~ /^#\d+/;	# loading by ordinal
+	my $addr = (DynaLoader::dl_find_symbol($handle, uc $prefix.$name)
+		    || DynaLoader::dl_find_symbol($handle, $prefix.$name));
+	return sub {
+	  OS2::DLL::_call($name, $addr, $queue, @_);
+	} if $addr;
+	my $err = DynaLoader::dl_error();
+	$err =~ s/\s+at\s+\S+\s+line\s+\S+\s*\z//;
+	croak "Can't find symbol `$name' in DLL `$file': $err";
 }
-1;
-EOE
+
+sub find
+{
+	my $self   = shift;
+	my $file   = $self->{File};
+	my $p	   = ref $self;
+	foreach (@_) {
+		my $f = eval {$self->wrapper_REXX($_)} or return 0;
+		${"${p}::"}{$_} = sub { shift; $f->(@_) };
 	}
 	return 1;
 }
 
-bootstrap OS2::DLL;
+XSLoader::load 'OS2::DLL';
 
 1;
 __END__
@@ -104,45 +120,71 @@ See documentation of L<OS2::REXX> module
 =head1 SYNOPSIS
 
 	use OS2::DLL;
-	$emx_dll = OS2::DLL->load('emx');
+	$emx_dll = OS2::DLL->module('emx');
 	$emx_version = $emx_dll->emx_revision();
+	$func_emx_version = $emx_dll->wrapper_REXX('#128'); # emx_revision
+	$emx_version = $func_emx_version->();
 
 =head1 DESCRIPTION
 
-=head2 Load REXX DLL
+=head2 Create a DLL handle
 
-	$dll = load OS2::DLL NAME [, WHERE];
+	$dll = OS2::DLL->module( NAME [, WHERE] );
+
+Loads an OS/2 module NAME, looking in directories WHERE (adding the
+extension F<.dll>), if the DLL is not found there, loads in the usual OS/2 way
+(via LIBPATH and other settings).  Croaks with a verbose report on failure.
 
-NAME is DLL name, without path and extension.
+The DLL is not unloaded when the return value is destroyed.
 
-Directories are searched WHERE first (list of dirs), then environment
-paths PERL5REXX, PERLREXX, PATH or, as last resort, OS/2-ish search 
-is performed in default DLL path (without adding paths and extensions).
+=head2 Create a DLL handle (looking in some strange locations)
 
-The DLL is not unloaded when the variable dies.
+	$dll = OS2::DLL->new( NAME [, WHERE] );
 
-Returns DLL object reference, or undef on failure (in this case one can
-get the reason via C<DynaLoader::dl_error()>).
+Same as L<C<module>|Create a DLL handle>, but in addition to WHERE, looks
+in environment paths PERL5REXX, PERLREXX, PATH (provided for backward
+compatibility).
 
-=head2 Create a REXX DLL handle
+=head2 Loads DLL by name
 
-	$dll = OS2::DLL->new( NAME [, WHERE] );
+	$dll = load OS2::DLL NAME [, WHERE];
 
-Same as L<C<load>|Load REXX DLL>, but croaks with a meaningful message on
-failure.
+Same as L<C<new>|Create a DLL handle (looking in some strange locations)>,
+but returns DLL object reference, or undef on failure (in this case one can
+get the reason via C<DynaLoader::dl_error()>) (provided for backward
+compatibility).
 
 =head2 Check for functions (optional):
 
 	BOOL = $dll->find(NAME [, NAME [, ...]]);
 
-Returns true if all functions are available.
+Returns true if all functions are available.  As a side effect, creates
+a REXX wrapper with the specified name in the package constructed by the name
+of the DLL so that the next call to C<$dll->NAME()> will pick up the cached
+method.
+
+=head2 Create a Perl wrapper (optional):
+
+	$func = $dll->wrapper_REXX(NAME);
+
+Returns a reference to a Perl function wrapper for the entry point NAME
+in the DLL.  Similar to the OS/2 API, the NAME may be C<"#123"> - in this case
+the ordinal is loaded.   Croaks with a meaningful error message if NAME does
+not exists (although the message for the case when the name is an ordinal may
+be confusing).
+
+=head2 Call external function with REXX calling convention:
 
-=head2 Call external REXX function:
+	$ret_string = $dll->function_name(arguments);
 
-	$dll->function(arguments);
+Returns the return string if the REXX return code is 0, else undef.
+Dies with error message if the function is not available.  On the first call
+resolves the name in the DLL and caches the Perl wrapper; future calls go
+through the wrapper.
 
-Returns the return string if the return code is 0, else undef.
-Dies with error message if the function is not available.
+Unless used inside REXX environment (see L<OS2::REXX>), the REXX runtime
+environment (variable pool, queue etc.) is not available to the called
+function.
 
 =head1 ENVIRONMENT
 
@@ -151,7 +193,7 @@ in C<PERL5REXX>, C<PERLREXX>, C<PATH>.
 
 =head1 AUTHOR
 
-Extracted by Ilya Zakharevich ilya@math.ohio-state.edu from L<OS2::REXX>
+Extracted by Ilya Zakharevich perl-module-OS2-DLL@ilyaz.org from L<OS2::REXX>
 written by Andreas Kaiser ak@ananke.s.bawue.de.
 
 =cut
--- ./os2/OS2/Process/Process.pm-pre	Fri Jul 19 16:50:02 2002
+++ ./os2/OS2/Process/Process.pm	Wed Jun 11 03:04:06 2003
@@ -101,6 +101,7 @@ our @EXPORT = qw(
 	ChildWindows
 	out_codepage
 	out_codepage_set
+	process_codepage_set
 	in_codepage
 	in_codepage_set
 	cursor
@@ -124,6 +125,36 @@ our @EXPORT = qw(
         SetWindowPtr
         SetWindowULong
         SetWindowUShort
+	TopLevel
+	FocusWindow_set_keep_Zorder
+
+	ActiveDesktopPathname
+	InvalidateRect
+	CreateFrameControl
+	ClipbrdFmtInfo
+	ClipbrdOwner
+	ClipbrdViewer
+	ClipbrdData
+	OpenClipbrd
+	CloseClipbrd
+	ClipbrdData_set
+	ClipbrdOwner_set
+	ClipbrdViewer_set
+	EnumClipbrdFmts
+	EmptyClipbrd
+	AddAtom
+	FindAtom
+	DeleteAtom
+	AtomUsage
+	AtomName
+	AtomLength
+	SystemAtomTable
+	CreateAtomTable
+	DestroyAtomTable
+
+	_ClipbrdData_set
+	ClipbrdText
+	ClipbrdText_set
 
 	get_title
 	set_title
@@ -335,6 +366,43 @@ sub ChildWindows (;$) {
   @kids;
 }
 
+sub TopLevel ($) {
+  my $d = DesktopWindow;
+  my $w = shift;
+  while (1) {
+    my $p = QueryWindow $w, 5;	# QW_PARENT;
+    return $w if not $p or $p == $d;
+    $w = $p;
+  }
+}
+
+sub FocusWindow_set_keep_Zorder ($) {
+  my $w = shift;
+  my $t = TopLevel $w;
+  my $b = hWindowPos($t)->{behind}; # we are behind this
+  EnableWindowUpdate($t, 0);
+  FocusWindow_set($w);
+# sleep 1;    # Make flicker stronger when present
+  hWindowPos_set {behind => $b}, $t;
+  EnableWindowUpdate($t, 1);
+}
+
+sub ClipbrdText (@) {
+  my $morph = OS2::localMorphPM->new(0);
+  OpenClipbrd();
+  my $txt = unpack 'p', pack 'L', ClipbrdData @_;
+  CloseClipbrd();
+  $txt;
+}
+
+sub ClipbrdText_set ($;$) {
+  my $morph = OS2::localMorphPM->new(0);
+  OpenClipbrd();
+  my ($txt, $no_convert_nl) = (shift, shift);
+  ClipbrdData_set($txt, !$no_convert_nl, @_);
+  CloseClipbrd();
+}
+
 # backward compatibility
 *set_title = \&Title_set;
 *get_title = \&Title;
@@ -551,7 +619,19 @@ gets a buffer with characters and attrib
 
 =item C<screen_set($buffer)>
 
-restores the screen given the result of screen().
+restores the screen given the result of screen().  E.g., if the file
+C<$file> contains the sceen contents, then
+
+  open IN, $file or die;
+  binmode IN;
+  read IN, $in, -s IN;
+  $s = screen;
+  $in .= qq(\0) x (length($s) - length $in);
+  substr($in, length $s) = '';
+  screen_set $in;
+
+will restore the screen content even if the height of the window
+changed (if the width changed, more manipulation is needed).
 
 =back
 
@@ -705,9 +785,9 @@ titlebar of the current window.
 sets text of the titlebar and task switch menu of the current process' window
 via direct manipulation of the windows' texts.
 
-=item C<SwitchToProgram($sw_entry)>
+=item C<SwitchToProgram([$sw_entry])>
 
-switch to session given by a switch list handle.
+switch to session given by a switch list handle (defaults to the entry of our process).
 
 Use of this function causes another window (and its related windows)
 of a PM session to appear on the front of the screen, or a switch to
@@ -824,10 +904,18 @@ to use.  E.g, the first entry in program
 To show an application, use either one of
 
        WinShowWindow( $hwnd, 1 );
-       SetFocus( $hwnd );
+       FocusWindow_set( $hwnd );
        SwitchToProgram($switch_handle);
 
-(Which work with alternative focus-to-front policies?)  Requires (morphing to) PM.
+(Which work with alternative focus-to-front policies?)  Requires
+(morphing to) PM.
+
+Switching focus to currently-unfocused window moves the window to the
+front in Z-order; use FocusWindow_set_keep_Zorder() to avoid this.
+
+=item C<FocusWindow_set_keep_Zorder($hwnd)>
+
+same as FocusWindow_set(), but preserves the Z-order of windows.
 
 =item C<ActiveWindow([$parentHwnd])>
 
@@ -1013,6 +1101,16 @@ item list when beginning is reached.
 
 =back
 
+=item DesktopWindow()
+
+gets the actual window handle of the PM desktop; most APIs accept the
+pseudo-handle C<HWND_DESKTOP> instead.  Keep in mind that the WPS
+desktop (one with WindowText() being C<"Desktop">) is a different beast?!
+
+=item TopLevel($hwnd)
+
+gets the toplevel window of $hwnd.
+
 =item ResetWinError()
 
 Resets $^E.  One may need to call it before the C<Win*>-class APIs which may
@@ -1031,6 +1129,77 @@ This function is normally not needed.  N
 
 =back
 
+=head2 Control of the PM data
+
+=over
+
+=item ActiveDesktopPathname()
+
+gets the path of the directory which corresponds to Desktop.
+
+=item ClipbrdText()
+
+gets the content of the clipboard.  An optional argument is the format
+of the data in the clipboard (defaults to C<CF_TEXT>).
+
+Note that the usual convention is to have clipboard data with
+C<"\r\n"> as line separators.
+
+=item ClipbrdText_set($txt)
+
+sets the text content of the clipboard.  Unless the optional argument
+is TRUE, will convert newlines to C<"\r\n">.  Another optional
+argument is the format of the data in the clipboard (defaults to
+C<CF_TEXT>).
+
+=item 	InvalidateRect
+
+=item	CreateFrameControl
+
+=item	ClipbrdFmtInfo
+
+=item	ClipbrdOwner
+
+=item	ClipbrdViewer
+
+=item	ClipbrdData
+
+=item	OpenClipbrd
+
+=item	CloseClipbrd
+
+=item	ClipbrdData_set
+
+=item	ClipbrdOwner_set
+
+=item	ClipbrdViewer_set
+
+=item	EnumClipbrdFmts
+
+=item	EmptyClipbrd
+
+=item	AddAtom
+
+=item	FindAtom
+
+=item	DeleteAtom
+
+=item	AtomUsage
+
+=item	AtomName
+
+=item	AtomLength
+
+=item	SystemAtomTable
+
+=item	CreateAtomTable
+
+=item	DestroyAtomTable
+
+Low-level methods to access clipboard and the atom table(s).
+
+=back
+
 =head1 OS2::localMorphPM class
 
 This class morphs the process to PM for the duration of the given scope.
@@ -1072,12 +1241,14 @@ Add tests for:
 	scrsize
 	scrsize_set
 
-Document:
-Query/SetWindowULong/Short/Ptr, SetWindowBits.
+Document and test: Query/SetWindowULong/Short/Ptr, SetWindowBits.
+InvalidateRect, CreateFrameControl, ClipbrdFmtInfo ClipbrdOwner
+ClipbrdViewer ClipbrdData OpenClipbrd CloseClipbrd ClipbrdData_set
+ClipbrdOwner_set ClipbrdViewer_set EnumClipbrdFmts EmptyClipbrd
+AddAtom FindAtom DeleteAtom AtomUsage AtomName AtomLength
+SystemAtomTable CreateAtomTable DestroyAtomTable
 
-Implement InvalidateRect,
-CreateFrameControl. ClipbrdFmtInfo, ClipbrdData, OpenClipbrd, CloseClipbrd,
-ClipbrdData_set, EnumClipbrdFmt, EmptyClipbrd.  SOMETHINGFROMMR.
+Implement SOMETHINGFROMMR.
 
 
   >But I wish to change the default button if the user enters some
--- ./os2/OS2/Process/Process.xs-pre	Fri Jul 19 16:50:02 2002
+++ ./os2/OS2/Process/Process.xs	Wed Jun 11 02:55:48 2003
@@ -7,12 +7,22 @@
 #define INCL_WININPUT
 #define INCL_VIO
 #define INCL_KBD
+#define INCL_WINCLIPBOARD
+#define INCL_WINATOM
 #include <os2.h>
 
 #include "EXTERN.h"
 #include "perl.h"
 #include "XSUB.h"
 
+static void croak_with_os2error(char *s) __attribute__((noreturn));
+
+void
+croak_with_os2error(char *s)
+{
+    Perl_croak_nocontext("%s: %s", s, os2error(Perl_rc));
+}
+
 static unsigned long
 constant(char *name, int arg)
 {
@@ -234,12 +244,14 @@ file_type(char *path)
     if (!(_emx_env & 0x200)) 
 	croak("file_type not implemented on DOS"); /* not OS/2. */
     if (CheckOSError(DosQueryAppType(path, &apptype))) {
+#if 0
 	if (rc == ERROR_INVALID_EXE_SIGNATURE) 
 	    croak("Invalid EXE signature"); 
 	else if (rc == ERROR_EXE_MARKED_INVALID) {
 	    croak("EXE marked invalid"); 
 	}
-	croak("DosQueryAppType err %ld", rc); 
+#endif
+	croak_with_os2error("DosQueryAppType"); 
     }
     
     return apptype;
@@ -260,7 +272,7 @@ DeclFuncByORD(ULONG, XmyWinSwitchToProgr
 #define myWinSwitchToProgram(hsw) (!CheckOSError(XmyWinSwitchToProgram(hsw)))
 
 
-
+/* These function croak if the return value is 0. */
 DeclWinFunc_CACHE(HWND, QueryWindow, (HWND hwnd, LONG cmd), (hwnd, cmd))
 DeclWinFunc_CACHE(BOOL, QueryWindowPos, (HWND hwnd, PSWP pswp),
 		  (hwnd, pswp))
@@ -300,6 +312,49 @@ DeclWinFunc_CACHE(HWND, EnumDlgItem, (HW
 DeclWinFunc_CACHE(HWND, QueryDesktopWindow, (HAB hab, HDC hdc), (hab, hdc));
 DeclWinFunc_CACHE(BOOL, SetActiveWindow, (HWND hwndDesktop, HWND hwnd),
 		  (hwndDesktop, hwnd));
+DeclWinFunc_CACHE(BOOL, QueryActiveDesktopPathname, (PSZ pszPathName, ULONG ulSize),
+		  (pszPathName, ulSize));
+DeclWinFunc_CACHE(BOOL, InvalidateRect,
+		  (HWND hwnd, /*RECTL*/ char *prcl, BOOL fIncludeChildren),
+		  (hwnd, prcl, fIncludeChildren));
+DeclWinFunc_CACHE(BOOL, CreateFrameControls,
+		  (HWND hwndFrame, /*PFRAMECDATA*/ char* pfcdata, PCSZ pszTitle),
+		  (hwndFrame, pfcdata, pszTitle));
+DeclWinFunc_CACHE(BOOL, OpenClipbrd, (HAB hab), (hab));
+DeclWinFunc_CACHE(BOOL, EmptyClipbrd, (HAB hab), (hab));
+DeclWinFunc_CACHE(BOOL, CloseClipbrd, (HAB hab), (hab));
+DeclWinFunc_CACHE(HWND, QueryClipbrdViewer, (HAB hab), (hab));
+DeclWinFunc_CACHE(HWND, QueryClipbrdOwner, (HAB hab), (hab));
+DeclWinFunc_CACHE(BOOL, QueryClipbrdFmtInfo, (HAB hab, ULONG fmt, PULONG prgfFmtInfo), (hab, fmt, prgfFmtInfo));
+DeclWinFunc_CACHE(ULONG, QueryClipbrdData, (HAB hab, ULONG fmt), (hab, fmt));
+DeclWinFunc_CACHE(HWND, SetClipbrdViewer, (HAB hab, HWND hwnd), (hab, hwnd));
+DeclWinFunc_CACHE(HWND, SetClipbrdOwner, (HAB hab, HWND hwnd), (hab, hwnd));
+DeclWinFunc_CACHE(ULONG, EnumClipbrdFmts, (HAB hab, ULONG fmt), (hab, fmt));
+DeclWinFunc_CACHE(ATOM, AddAtom, (HATOMTBL hAtomTbl, PCSZ pszAtomName),
+		  (hAtomTbl, pszAtomName));
+DeclWinFunc_CACHE(ATOM, FindAtom, (HATOMTBL hAtomTbl, PCSZ pszAtomName),
+		  (hAtomTbl, pszAtomName));
+DeclWinFunc_CACHE(ATOM, DeleteAtom, (HATOMTBL hAtomTbl, PCSZ pszAtomName),
+		  (hAtomTbl, pszAtomName));
+DeclWinFunc_CACHE(ULONG, QueryAtomUsage, (HATOMTBL hAtomTbl, ATOM atom),
+		  (hAtomTbl, atom));
+DeclWinFunc_CACHE(ULONG, QueryAtomLength, (HATOMTBL hAtomTbl, ATOM atom),
+		  (hAtomTbl, atom));
+DeclWinFunc_CACHE(ULONG, QueryAtomName,
+		  (HATOMTBL hAtomTbl, ATOM atom, PSZ pchBuffer, ULONG cchBufferMax),
+		  (hAtomTbl, atom, pchBuffer, cchBufferMax));
+DeclWinFunc_CACHE(HATOMTBL, QuerySystemAtomTable, (VOID), ());
+DeclWinFunc_CACHE(HATOMTBL, CreateAtomTable, (ULONG initial, ULONG buckets),
+		  (initial, buckets));
+DeclWinFunc_CACHE(HATOMTBL, DestroyAtomTable, (HATOMTBL hAtomTbl), (hAtomTbl));
+
+/* These functions do not croak on error */
+DeclWinFunc_CACHE_survive(BOOL, SetClipbrdData,
+			  (HAB hab, ULONG ulData, ULONG fmt, ULONG rgfFmtInfo),
+			  (hab, ulData, fmt, rgfFmtInfo));
+
+#define get_InvalidateRect	InvalidateRect
+#define get_CreateFrameControls	CreateFrameControls
 
 /* These functions may return 0 on success; check $^E/Perl_rc on res==0: */
 DeclWinFunc_CACHE_resetError(PVOID, QueryWindowPtr, (HWND hwnd, LONG index),
@@ -334,6 +389,9 @@ HWND (*pWinWindowFromPoint)(HWND hwnd, _
 #define WindowPos_set(hwnd, x, y, fl, cx, cy, hwndInsertBehind)	\
 	SetWindowPos(hwnd, hwndInsertBehind, x, y, cx, cy, fl)
 #define myWinQueryWindowPtr(hwnd, i)	((ULONG)QueryWindowPtr(hwnd, i))
+#define _ClipbrdData_set SetClipbrdData
+#define ClipbrdOwner_set SetClipbrdOwner
+#define ClipbrdViewer_set SetClipbrdViewer
 
 int
 WindowText_set(HWND hwnd, char* text)
@@ -411,20 +469,29 @@ WindowFromPoint(long x, long y, HWND hwn
     return SaveWinError(pWinWindowFromPoint(hwnd, &ppl, fChildren));
 }
 
-static void
-fill_swentry(SWENTRY *swentryp, HWND hwnd, PID pid)
+static HSWITCH
+switch_of(HWND hwnd, PID pid)
 {
-	 int rc;
 	 HSWITCH hSwitch;    
 
 	 if (!(_emx_env & 0x200)) 
 	     croak("switch_entry not implemented on DOS"); /* not OS/2. */
 	 if (CheckWinError(hSwitch = 
 			   myWinQuerySwitchHandle(hwnd, pid)))
-	     croak("WinQuerySwitchHandle: %s", os2error(Perl_rc));
+	     croak_with_os2error("WinQuerySwitchHandle");
+	 return hSwitch;
+}
+
+
+static void
+fill_swentry(SWENTRY *swentryp, HWND hwnd, PID pid)
+{
+	 int rc;
+	 HSWITCH hSwitch = switch_of(hwnd, pid);
+
 	 swentryp->hswitch = hSwitch;
 	 if (CheckOSError(myWinQuerySwitchEntry(hSwitch, &swentryp->swctl)))
-	     croak("WinQuerySwitchEntry err %ld", rc);
+	     croak_with_os2error("WinQuerySwitchEntry");
 }
 
 static void
@@ -433,6 +500,75 @@ fill_swentry_default(SWENTRY *swentryp)
 	fill_swentry(swentryp, NULLHANDLE, getpid());
 }
 
+static SV*
+myWinQueryActiveDesktopPathname()
+{
+    SV *buf = newSVpv("",0);
+    STRLEN n_a;
+
+    SvGROW(buf, MAXPATHLEN);
+    QueryActiveDesktopPathname(SvPV(buf,n_a), MAXPATHLEN);
+    SvCUR_set(buf, strlen(SvPV(buf, n_a)));
+    return buf;
+}
+
+SV *
+myWinQueryAtomName(ATOM atom, HATOMTBL hAtomTbl)
+{
+    ULONG len = QueryAtomLength(hAtomTbl, atom);
+    SV *sv = newSVpvn("",0);
+    STRLEN n_a;
+
+    SvGROW(sv, len + 1);
+    QueryAtomName(hAtomTbl, atom, SvPV(sv, n_a), len);
+    SvCUR_set(sv, len);
+    *SvEND(sv) = 0;
+    return sv;
+}
+
+#define myWinQueryClipbrdFmtInfo	QueryClipbrdFmtInfo
+
+/* Put data into shared memory, then call SetClipbrdData */
+void
+ClipbrdData_set(SV *sv, int convert_nl, unsigned long fmt, unsigned long rgfFmtInfo, unsigned long hab)
+{
+    STRLEN len;
+    char *buf = SvPV_force(sv, len);
+    char *pByte = 0, *s = buf, c;
+    ULONG nls = 0, rc;
+
+    if (convert_nl) {
+	while ((c = *s++)) {
+	    if (c == '\r' && *s == '\n')
+		s++;
+	    else if (c == '\n')
+		nls++;
+	}
+    }
+
+    if (CheckOSError(DosAllocSharedMem((PPVOID)&pByte, 0, len + nls + 1,
+				       PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE | OBJ_GETTABLE)))
+	croak_with_os2error("ClipbrdData_set: DosAllocSharedMem error");
+
+    if (!nls)
+	memcpy(pByte, buf, len + 1);
+    else {
+	char *t = pByte, *e = buf + len;
+
+	while (buf < e) {
+	    c = *t++ = *buf++;
+	    if (c == '\n' && (t == pByte + 1 || t[-2] != '\r'))
+		t[-1] = '\r', *t++ = '\n';
+	}
+    }
+
+    if (!SetClipbrdData(hab, (ULONG)pByte, fmt, rgfFmtInfo)) {
+	DosFreeMem((PPVOID)&pByte);
+	croak_with_os2error("ClipbrdData_set: WinSetClipbrdData error");
+    }
+}
+
+
 /* static ULONG (* APIENTRY16 pDosSmSetTitle)(ULONG, PSZ); */
 ULONG _THUNK_FUNCTION(DosSmSetTitle)(ULONG, PSZ);
 
@@ -660,7 +796,7 @@ cursor(int *sp, int *ep, int *wp, int *a
     VIO_FROM_VIOB;
 
     if (CheckOSError(VioGetCurType( vio, 0 )))
-	croak("VioGetCurType() error");
+	croak_with_os2error("VioGetCurType() error");
 
     *sp = vio->yStart;
     *ep = vio->cEnd;
@@ -706,7 +842,7 @@ bufsize(void)
 
     vio->cb = sizeof(*vio);
     if (CheckOSError(VioGetMode( vio, 0 )))
-	croak("Can't get size of buffer for screen");
+	croak_with_os2error("Can't get size of buffer for screen");
 #if 0	/* buf=323552247, full=1118455, partial=0 */
     croak("Lengths: buf=%d, full=%d, partial=%d",vio->buf_length,vio->full_length,vio->partial_length);
     return newSVpvn((char*)vio->buf_addr, vio->full_length);
@@ -766,7 +902,7 @@ process_codepages()
     ULONG cps[4], cp, rc;
 
     if (CheckOSError(DosQueryCp( sizeof(cps), cps, &cp )))
-	croak("DosQueryCp() error");
+	croak_with_os2error("DosQueryCp()");
     return cp;
 }
 
@@ -776,7 +912,7 @@ out_codepage()
     USHORT cp, rc;
 
     if (CheckOSError(VioGetCp( 0, &cp, 0 )))
-	croak("VioGetCp() error");
+	croak_with_os2error("VioGetCp()");
     return cp;
 }
 
@@ -794,7 +930,7 @@ in_codepage()
     USHORT cp, rc;
 
     if (CheckOSError(KbdGetCp( 0, &cp, 0 )))
-	croak("KbdGetCp() error");
+	croak_with_os2error("KbdGetCp()");
     return cp;
 }
 
@@ -1039,6 +1175,42 @@ cursor(OUTLIST int stp, OUTLIST int ep, 
 bool
 cursor_set(int s, int e, int w = cursor__(0), int a = cursor__(1))
 
+NO_OUTPUT bool
+_ClipbrdData_set(unsigned long ulData, unsigned long fmt = CF_TEXT, unsigned long rgfFmtInfo = ((fmt == CF_TEXT || fmt == CF_DSPTEXT) ? CFI_POINTER : CFI_HANDLE), unsigned long hab = perl_hab_GET())
+    PROTOTYPE: DISABLE
+    C_ARGS: hab, ulData, fmt, rgfFmtInfo
+    POSTCALL:
+	if (CheckWinError(RETVAL))
+	    croak_with_os2error("_ClipbrdData_set() error");
+
+void
+ClipbrdData_set(SV *text, int convert_nl = 1, unsigned long fmt = CF_TEXT, unsigned long rgfFmtInfo = ((fmt == CF_TEXT || fmt == CF_DSPTEXT) ? CFI_POINTER : CFI_HANDLE), unsigned long hab = perl_hab_GET())
+    PROTOTYPE: DISABLE
+
+void
+ClipbrdOwner_set(unsigned long hwnd, unsigned long hab = perl_hab_GET())
+    C_ARGS: hab, hwnd
+
+void
+ClipbrdViewer_set(unsigned long hwnd, unsigned long hab = perl_hab_GET())
+    C_ARGS: hab, hwnd
+
+unsigned long
+EnumClipbrdFmts(unsigned long fmt = 0, unsigned long hab = perl_hab_GET())
+    C_ARGS: hab, fmt
+
+unsigned long
+AddAtom(char *pszAtomName, unsigned long hAtomTbl = WinQuerySystemAtomTable())
+    C_ARGS: hAtomTbl, pszAtomName
+
+unsigned long
+FindAtom(char *pszAtomName, unsigned long hAtomTbl = WinQuerySystemAtomTable())
+    C_ARGS: hAtomTbl, pszAtomName
+
+unsigned long
+DeleteAtom(char *pszAtomName, unsigned long hAtomTbl = WinQuerySystemAtomTable())
+    C_ARGS: hAtomTbl, pszAtomName
+
 MODULE = OS2::Process		PACKAGE = OS2::Process	PREFIX = myQuery
 
 SV *
@@ -1070,6 +1242,44 @@ QueryActiveWindow(unsigned long hwnd = H
 unsigned long
 QueryDesktopWindow(unsigned long hab = Acquire_hab(), unsigned long hdc = NULLHANDLE)
 
+unsigned long
+QueryClipbrdData(unsigned long fmt = CF_TEXT, unsigned long hab = perl_hab_GET())
+    C_ARGS: hab, fmt
+    PROTOTYPE: DISABLE
+
+unsigned long
+QueryClipbrdViewer(unsigned long hab = perl_hab_GET())
+
+unsigned long
+QueryClipbrdOwner(unsigned long hab = perl_hab_GET())
+
+void
+CloseClipbrd(unsigned long hab = perl_hab_GET())
+
+void
+EmptyClipbrd(unsigned long hab = perl_hab_GET())
+
+bool
+OpenClipbrd(unsigned long hab = perl_hab_GET())
+
+unsigned long
+QueryAtomUsage(unsigned long atom, unsigned long hAtomTbl = WinQuerySystemAtomTable())
+    C_ARGS: hAtomTbl, atom
+
+unsigned long
+QueryAtomLength(unsigned long atom, unsigned long hAtomTbl = WinQuerySystemAtomTable())
+    C_ARGS: hAtomTbl, atom
+
+unsigned long
+QuerySystemAtomTable()
+
+unsigned long
+CreateAtomTable(unsigned long initial = 0, unsigned long buckets = 0)
+
+unsigned long
+DestroyAtomTable(unsigned long hAtomTbl)
+
+
 MODULE = OS2::Process		PACKAGE = OS2::Process	PREFIX = myWinQuery
 
 unsigned long
@@ -1080,12 +1290,22 @@ myWinQueryWindowProcess(unsigned long hw
    PROTOTYPE: $
    POSTCALL:
 	if (CheckWinError(RETVAL))
-	    croak("WindowProcess() error");
+	    croak_with_os2error("WindowProcess() error");
+
+SV *
+myWinQueryActiveDesktopPathname()
+
+void
+myWinQueryClipbrdFmtInfo(OUTLIST unsigned long prgfFmtInfo, unsigned long fmt = CF_TEXT, unsigned long hab = perl_hab_GET())
+   C_ARGS: hab, fmt, &prgfFmtInfo
+
+SV *
+myWinQueryAtomName(unsigned long atom, unsigned long hAtomTbl = WinQuerySystemAtomTable())
 
 MODULE = OS2::Process		PACKAGE = OS2::Process	PREFIX = myWin
 
 int
-myWinSwitchToProgram(unsigned long hsw)
+myWinSwitchToProgram(unsigned long hsw = switch_of(NULLHANDLE, getpid()))
     PREINIT:
 	ULONG rc;
 
@@ -1108,6 +1328,12 @@ getscrsize(OUTLIST int wp, OUTLIST int h
 
 bool
 scrsize_set(int w_or_h, int h = -9999)
+
+void
+get_InvalidateRect(unsigned long hwnd, char *prcl, bool fIncludeChildren)
+
+void
+get_CreateFrameControls(unsigned long hwndFrame, char *pfcdata, char* pszTitle)
 
 MODULE = OS2::Process		PACKAGE = OS2::Process	PREFIX = ul
 
--- ./ext/Time/HiRes/Makefile.PL-pre	Tue Mar 11 11:34:34 2003
+++ ./ext/Time/HiRes/Makefile.PL	Mon May 26 19:04:22 2003
@@ -14,6 +14,8 @@ my $DEFINE;
 my $LIBS;
 my $XSOPT;
 
+my $ld_exeext = ($^O eq 'os2' and $Config{ldflags} =~ /-Zexe\b/) ? '.exe' : '';
+
 unless($ENV{PERL_CORE}) { # This trick from Encode/Makefile.PL.
     $ENV{PERL_CORE} = 1 if ($^X =~ m{\bminiperl[^/\\\]>:]*$}o);
 }
@@ -139,10 +141,11 @@ sub try_compile_and_link {
         }
         else
         {
+	    my $tmp_exe = "$tmp$ld_exeext";
 	    printf "cccmd = $cccmd\n" if $VERBOSE;
-	    system($cccmd);
-	    $ok = -s $tmp && -x _;
-	    unlink("$tmp.c", $tmp);
+	    my $res = system($cccmd);
+	    $ok = defined($res) && $res==0 && -s $tmp_exe && -x _;
+	    unlink("$tmp.c", $tmp_exe);
         }
     }
     
@@ -367,7 +370,8 @@ EOD
         print "You can mix subsecond sleeps with signals.\n";
     } else {
 	print "NOT found.\n";
-        print "You cannot mix subsecond sleeps with signals.\n";
+	my $nt = ($^O eq 'os2' ? '' : 'not');
+        print "You can$nt mix subsecond sleeps with signals.\n";
     }
 
     if ($DEFINE) {
--- ./doio.c-as-sent	Wed Mar 19 22:33:18 2003
+++ ./doio.c	Mon May 26 16:06:00 2003
@@ -1380,11 +1380,13 @@ Perl_my_lstat(pTHX)
     return PL_laststatval;
 }
 
+#ifndef OS2
 bool
 Perl_do_aexec(pTHX_ SV *really, register SV **mark, register SV **sp)
 {
     return do_aexec5(really, mark, sp, 0, 0);
 }
+#endif
 
 bool
 Perl_do_aexec5(pTHX_ SV *really, register SV **mark, register SV **sp,
--- ./os2/dl_os2.c-as-sent	Sun Mar 30 15:06:32 2003
+++ ./os2/dl_os2.c	Mon May 26 01:43:30 2003
@@ -4,10 +4,15 @@
 
 #define INCL_BASE
 #include <os2.h>
+#include <float.h>
+#include <stdlib.h>
 
 static ULONG retcode;
 static char fail[300];
 
+static ULONG dllHandle;
+static int handle_found;
+static int handle_loaded;
 #ifdef PERL_CORE
 
 #include "EXTERN.h"
@@ -19,6 +24,57 @@ char *os2error(int rc);
 
 #endif
 
+#ifdef DLOPEN_INITTERM
+unsigned long _DLL_InitTerm(unsigned long modHandle, unsigned long flag)
+{
+    switch (flag) {
+    case 0:     /* INIT */
+        /* Save handle */
+        dllHandle = modHandle;
+	handle_found = 1;
+        return TRUE;
+
+    case 1:     /* TERM */
+	handle_found = 0;
+        dllHandle = (unsigned long)NULLHANDLE;
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+#endif
+
+HMODULE
+find_myself(void)
+{
+
+  static APIRET APIENTRY (*pDosQueryModFromEIP) (HMODULE * hmod, ULONG * obj, ULONG BufLen, PCHAR Buf,
+		    ULONG * Offset, ULONG Address);
+  HMODULE doscalls_h, mod;
+  static int failed;
+  ULONG obj, offset, rc;
+  char buf[260];
+
+  if (failed)
+	return 0;
+  failed = 1;
+  doscalls_h = (HMODULE)dlopen("DOSCALLS",0);
+  if (!doscalls_h)
+	return 0;
+/*  {&doscalls_handle, NULL, 360}, */	/* DosQueryModFromEIP */
+  rc = DosQueryProcAddr(doscalls_h, 360, 0, (PFN*)&pDosQueryModFromEIP);
+  if (rc)
+	return 0;
+  rc = pDosQueryModFromEIP(&mod, &obj, sizeof(buf), buf, &offset, (ULONG)dlopen);
+  if (rc)
+	return 0;
+  failed = 0;
+  handle_found = 1;
+  dllHandle = mod;
+  return mod;
+}
+
 void *
 dlopen(const char *path, int mode)
 {
@@ -26,10 +82,36 @@ dlopen(const char *path, int mode)
 	char tmp[260];
 	const char *beg, *dot;
 	ULONG rc;
+	unsigned fpflag = _control87(0,0);
 
 	fail[0] = 0;
+	if (!path) {			/* Our own handle. */
+	    if (handle_found || find_myself()) {
+		char dllname[260];
+
+		if (handle_loaded)
+		    return (void*)dllHandle;
+		rc = DosQueryModuleName(dllHandle, sizeof(dllname), dllname);
+		if (rc) {
+	            strcpy(fail, "can't find my DLL name by the handle");
+		    retcode = rc;
+		    return 0;
+		}
+		rc = DosLoadModule(fail, sizeof fail, dllname, &handle);
+		if (rc) {
+	            strcpy(fail, "can't load my own DLL");
+		    retcode = rc;
+		    return 0;
+		}
+		handle_loaded = 1;
+		goto ret;
+	    }
+	    retcode = ERROR_MOD_NOT_FOUND;
+            strcpy(fail, "can't load from myself: compiled without -DDLOPEN_INITTERM");
+	    return 0;
+	}
 	if ((rc = DosLoadModule(fail, sizeof fail, (char*)path, &handle)) == 0)
-		return (void *)handle;
+		goto ret;
 
 	retcode = rc;
 
@@ -49,12 +131,17 @@ dlopen(const char *path, int mode)
 		memmove(tmp, path, n);
 		memmove(tmp+n, dot, strlen(dot)+1);
 		if (DosLoadModule(fail, sizeof fail, tmp, &handle) == 0)
-			return (void *)handle;
+		    goto ret;
 	}
+	handle = 0;
 
-	return NULL;
+      ret:
+	_control87(fpflag, MCW_EM); /* Some modules reset FP flags on load */
+	return (void *)handle;
 }
 
+#define ERROR_WRONG_PROCTYPE 0xffffffff
+
 void *
 dlsym(void *handle, const char *symbol)
 {
@@ -67,7 +154,7 @@ dlsym(void *handle, const char *symbol)
 		rc = DosQueryProcType((HMODULE)handle, 0, symbol, &type);
 		if (rc == 0 && type == PT_32BIT)
 			return (void *)addr;
-		rc = ERROR_CALL_NOT_IMPLEMENTED;
+		rc = ERROR_WRONG_PROCTYPE;
 	}
 	retcode = rc;
 	return NULL;
@@ -82,12 +169,15 @@ dlerror(void)
 
 	if (retcode == 0)
 		return NULL;
-	err = os2error(retcode);
+	if (retcode == ERROR_WRONG_PROCTYPE)
+	    err = "Wrong procedure type";
+	else
+	    err = os2error(retcode);
 	len = strlen(err);
 	if (len > sizeof(buf) - 1)
 	    len = sizeof(buf) - 1;
 	strncpy(buf, err, len+1);
-	if (fail[0] && len < 300)
+	if (fail[0] && len + strlen(fail) < sizeof(buf) - 100)
 	    sprintf(buf + len, ", possible problematic module: '%s'", fail);
 	retcode = 0;
 	return buf;
--- ./os2/os2.c-as-sent	Sun Mar 30 15:14:12 2003
+++ ./os2/os2.c	Wed Jun 11 02:43:38 2003
@@ -3,6 +3,7 @@
 #define INCL_DOSFILEMGR
 #define INCL_DOSMEMMGR
 #define INCL_DOSERRORS
+#define INCL_WINERRORS
 /* These 3 are needed for compile if os2.h includes os2tk.h, not os2emx.h */
 #define INCL_DOSPROCESS
 #define SPU_DISABLESUPPRESSION          0
@@ -30,6 +31,153 @@
 #include "EXTERN.h"
 #include "perl.h"
 
+#define C_ARR_LEN(sym)	(sizeof(sym)/sizeof(*sym))
+
+struct PMWIN_entries_t PMWIN_entries;
+
+/*****************************************************************************/
+/* 2.1 would not resolve symbols on demand, and has no ExtLIBPATH. */
+
+struct dll_handle_t {
+    const char *modname;
+    HMODULE handle;
+};
+
+static struct dll_handle_t dll_handles[] = {
+    {"doscalls", 0},
+    {"tcp32dll", 0},
+    {"pmwin", 0},
+    {"rexx", 0},
+    {"rexxapi", 0},
+    {"sesmgr", 0},
+    {"pmshapi", 0},
+    {"pmwp", 0},
+    {NULL, 0},
+};
+
+enum dll_handle_e {
+    dll_handle_doscalls,
+    dll_handle_tcp32dll,
+    dll_handle_pmwin,
+    dll_handle_rexx,
+    dll_handle_rexxapi,
+    dll_handle_sesmgr,
+    dll_handle_pmshapi,
+    dll_handle_pmwp,
+    dll_handle_LAST,
+};
+
+#define doscalls_handle		(dll_handles[dll_handle_doscalls])
+#define tcp_handle		(dll_handles[dll_handle_tcp32dll])
+#define pmwin_handle		(dll_handles[dll_handle_pmwin])
+#define rexx_handle		(dll_handles[dll_handle_rexx])
+#define rexxapi_handle		(dll_handles[dll_handle_rexxapi])
+#define sesmgr_handle		(dll_handles[dll_handle_sesmgr])
+#define pmshapi_handle		(dll_handles[dll_handle_pmshapi])
+#define pmwp_handle		(dll_handles[dll_handle_pmwp])
+
+/*  The following local-scope data is not yet included:
+       fargs.140			// const => OK
+       ino.165				// locked - and the access is almost cosmetic
+       layout_table.260			// startup only, locked
+       osv_res.257			// startup only, locked
+       old_esp.254			// startup only, locked
+       priors				// const ==> OK
+       use_my_flock.283			// locked
+       emx_init_done.268		// locked
+       dll_handles			// locked
+       hmtx_emx_init.267		// THIS is the lock for startup
+       perlos2_state_mutex		// THIS is the lock for all the rest
+BAD:
+       perlos2_state			// see below
+*/
+/*  The following global-scope data is not yet included:
+       OS2_Perl_data
+       at_exit_buf
+       emx_exception_init
+       emx_runtime_init
+       emx_runtime_secondary
+       longjmp_at_exit
+       pDosVerifyPidTid
+       pthreads_states
+       start_thread_mutex
+       thread_join_count
+       thread_join_data
+       tmppath
+*/
+
+static struct perlos2_state_t {
+  int po2__my_pwent;				/* = -1; */
+  int po2_DOS_harderr_state;			/* = -1;    */
+  signed char po2_DOS_suppression_state;	/* = -1;    */
+  PFN po2_ExtFCN[ORD_NENTRIES];	/* Labeled by ord ORD_*. */
+/*  struct PMWIN_entries_t po2_PMWIN_entries; */
+
+  int po2_emx_wasnt_initialized;
+
+  char po2_fname[9];
+  int po2_rmq_cnt;
+
+  int po2_grent_cnt;
+
+  char *po2_newp;
+  char *po2_oldp;
+  int po2_newl;
+  int po2_oldl;
+  int po2_notfound;
+  char po2_mangle_ret[STATIC_FILE_LENGTH+1];
+  ULONG po2_os2_dll_fake;
+  ULONG po2_os2_mytype;
+  ULONG po2_os2_mytype_ini;
+  int po2_pidtid_lookup;
+  struct passwd po2_pw;
+
+  int po2_pwent_cnt;
+  char po2_pthreads_state_buf[80];
+  char po2_os2error_buf[300];
+/* There is no big sense to make it thread-specific, since signals 
+   are delivered to thread 1 only.  XXXX Maybe make it into an array? */
+  int po2_spawn_pid;
+  int po2_spawn_killed;
+} perlos2_state = {
+    -1,					/* po2__my_pwent */
+    -1,					/* po2_DOS_harderr_state */
+    -1,					/* po2_DOS_suppression_state */
+};
+
+#define Perl_po2()		(&perlos2_state)
+
+#define ExtFCN			(Perl_po2()->po2_ExtFCN)
+/* #define PMWIN_entries		(Perl_po2()->po2_PMWIN_entries) */
+#define emx_wasnt_initialized	(Perl_po2()->po2_emx_wasnt_initialized)
+#define fname			(Perl_po2()->po2_fname)
+#define rmq_cnt			(Perl_po2()->po2_rmq_cnt)
+#define grent_cnt		(Perl_po2()->po2_grent_cnt)
+#define newp			(Perl_po2()->po2_newp)
+#define oldp			(Perl_po2()->po2_oldp)
+#define newl			(Perl_po2()->po2_newl)
+#define oldl			(Perl_po2()->po2_oldl)
+#define notfound		(Perl_po2()->po2_notfound)
+#define mangle_ret		(Perl_po2()->po2_mangle_ret)
+#define os2_dll_fake		(Perl_po2()->po2_os2_dll_fake)
+#define os2_mytype		(Perl_po2()->po2_os2_mytype)
+#define os2_mytype_ini		(Perl_po2()->po2_os2_mytype_ini)
+#define pidtid_lookup		(Perl_po2()->po2_pidtid_lookup)
+#define pw			(Perl_po2()->po2_pw)
+#define pwent_cnt		(Perl_po2()->po2_pwent_cnt)
+#define _my_pwent		(Perl_po2()->po2__my_pwent)
+#define pthreads_state_buf	(Perl_po2()->po2_pthreads_state_buf)
+#define os2error_buf		(Perl_po2()->po2_os2error_buf)
+/* There is no big sense to make it thread-specific, since signals 
+   are delivered to thread 1 only.  XXXX Maybe make it into an array? */
+#define spawn_pid		(Perl_po2()->po2_spawn_pid)
+#define spawn_killed		(Perl_po2()->po2_spawn_killed)
+#define DOS_harderr_state	(Perl_po2()->po2_DOS_harderr_state)
+#define DOS_suppression_state		(Perl_po2()->po2_DOS_suppression_state)
+
+const Perl_PFN * const pExtFCN = (Perl_po2()->po2_ExtFCN);
+
+
 #if defined(USE_5005THREADS) || defined(USE_ITHREADS)
 
 typedef void (*emx_startroutine)(void *);
@@ -60,10 +208,9 @@ static const char*
 pthreads_state_string(enum pthreads_state state)
 {
   if (state < 0 || state >= sizeof(pthreads_states)/sizeof(*pthreads_states)) {
-    static char buf[80];
-
-    snprintf(buf, sizeof(buf), "unknown thread state %d", (int)state);
-    return buf;
+    snprintf(pthreads_state_buf, sizeof(pthreads_state_buf),
+	     "unknown thread state %d", (int)state);
+    return pthreads_state_buf;
   }
   return pthreads_states[state];
 }
@@ -77,6 +224,8 @@ typedef struct {
 thread_join_t *thread_join_data;
 int thread_join_count;
 perl_mutex start_thread_mutex;
+static perl_mutex perlos2_state_mutex;
+
 
 int
 pthread_join(perl_os_thread tid, void **status)
@@ -318,28 +467,12 @@ os2_cond_wait(perl_cond *c, perl_mutex *
 
 static int exe_is_aout(void);
 
-/*****************************************************************************/
-/* 2.1 would not resolve symbols on demand, and has no ExtLIBPATH. */
-#define C_ARR_LEN(sym)	(sizeof(sym)/sizeof(*sym))
-
-struct dll_handle {
-    const char *modname;
-    HMODULE handle;
-};
-static struct dll_handle doscalls_handle = {"doscalls", 0};
-static struct dll_handle tcp_handle = {"tcp32dll", 0};
-static struct dll_handle pmwin_handle = {"pmwin", 0};
-static struct dll_handle rexx_handle = {"rexx", 0};
-static struct dll_handle rexxapi_handle = {"rexxapi", 0};
-static struct dll_handle sesmgr_handle = {"sesmgr", 0};
-static struct dll_handle pmshapi_handle = {"pmshapi", 0};
-
 /* This should match enum entries_ordinals defined in os2ish.h. */
 static const struct {
-    struct dll_handle *dll;
+    struct dll_handle_t *dll;
     const char *entryname;
     int entrypoint;
-} loadOrdinals[ORD_NENTRIES] = { 
+} loadOrdinals[] = {
   {&doscalls_handle, NULL, 874},	/* DosQueryExtLibpath */
   {&doscalls_handle, NULL, 873},	/* DosSetExtLibpath */
   {&doscalls_handle, NULL, 460},	/* DosVerifyPidTid */
@@ -427,11 +560,32 @@ static const struct {
   {&pmwin_handle, NULL, 813},		/* WinQueryDesktopWindow */
   {&pmwin_handle, NULL, 851},		/* WinSetActiveWindow */
   {&doscalls_handle, NULL, 360},	/* DosQueryModFromEIP */
+  {&doscalls_handle, NULL, 582},	/* Dos32QueryHeaderInfo */
+  {&pmwp_handle, NULL, 262},		/* WinQueryActiveDesktopPathname */
+  {&pmwin_handle, NULL, 765},		/* WinInvalidateRect */
+  {&pmwin_handle, NULL, 906},		/* WinCreateFrameControl */
+  {&pmwin_handle, NULL, 807},		/* WinQueryClipbrdFmtInfo */
+  {&pmwin_handle, NULL, 808},		/* WinQueryClipbrdOwner */
+  {&pmwin_handle, NULL, 809},		/* WinQueryClipbrdViewer */
+  {&pmwin_handle, NULL, 806},		/* WinQueryClipbrdData */
+  {&pmwin_handle, NULL, 793},		/* WinOpenClipbrd */
+  {&pmwin_handle, NULL, 707},		/* WinCloseClipbrd */
+  {&pmwin_handle, NULL, 854},		/* WinSetClipbrdData */
+  {&pmwin_handle, NULL, 855},		/* WinSetClipbrdOwner */
+  {&pmwin_handle, NULL, 856},		/* WinSetClipbrdViewer */
+  {&pmwin_handle, NULL, 739},		/* WinEnumClipbrdFmts  */
+  {&pmwin_handle, NULL, 733},		/* WinEmptyClipbrd */
+  {&pmwin_handle, NULL, 700},		/* WinAddAtom */
+  {&pmwin_handle, NULL, 744},		/* WinFindAtom */
+  {&pmwin_handle, NULL, 721},		/* WinDeleteAtom */
+  {&pmwin_handle, NULL, 803},		/* WinQueryAtomUsage */
+  {&pmwin_handle, NULL, 802},		/* WinQueryAtomName */
+  {&pmwin_handle, NULL, 801},		/* WinQueryAtomLength */
+  {&pmwin_handle, NULL, 830},		/* WinQuerySystemAtomTable */
+  {&pmwin_handle, NULL, 714},		/* WinCreateAtomTable */
+  {&pmwin_handle, NULL, 724},		/* WinDestroyAtomTable */
 };
 
-static PFN ExtFCN[C_ARR_LEN(loadOrdinals)];	/* Labeled by ord ORD_*. */
-const Perl_PFN * const pExtFCN = ExtFCN;
-struct PMWIN_entries_t PMWIN_entries;
 
 HMODULE
 loadModule(const char *modname, int fail)
@@ -447,13 +601,20 @@ loadModule(const char *modname, int fail
 PFN
 loadByOrdinal(enum entries_ordinals ord, int fail)
 {
+    if (sizeof(loadOrdinals)/sizeof(loadOrdinals[0]) != ORD_NENTRIES)
+	    Perl_croak_nocontext(
+		 "Wrong size of loadOrdinals array: expected %d, actual %d", 
+		 sizeof(loadOrdinals)/sizeof(loadOrdinals[0]), ORD_NENTRIES);
     if (ExtFCN[ord] == NULL) {
 	PFN fcn = (PFN)-1;
 	APIRET rc;
 
-	if (!loadOrdinals[ord].dll->handle)
+	if (!loadOrdinals[ord].dll->handle) {
+	    MUTEX_LOCK(&perlos2_state_mutex);
 	    loadOrdinals[ord].dll->handle
 		= loadModule(loadOrdinals[ord].dll->modname, fail);
+	    MUTEX_UNLOCK(&perlos2_state_mutex);
+	}
 	if (!loadOrdinals[ord].dll->handle)
 	    return 0;			/* Possible with FAIL==0 only */
 	if (CheckOSError(DosQueryProcAddr(loadOrdinals[ord].dll->handle,
@@ -504,12 +665,11 @@ DeclVoidFuncByORD(endprotoent, ORD_ENDPR
 DeclVoidFuncByORD(endservent,  ORD_ENDSERVENT,  (void), ())
 
 /* priorities */
-static signed char priors[] = {0, 1, 3, 2}; /* Last two interchanged,
-					       self inverse. */
+static const signed char priors[] = {0, 1, 3, 2}; /* Last two interchanged,
+						     self inverse. */
 #define QSS_INI_BUFFER 1024
 
 ULONG (*pDosVerifyPidTid) (PID pid, TID tid);
-static int pidtid_lookup;
 
 PQTOPLEVEL
 get_sysinfo(ULONG pid, ULONG flags)
@@ -619,10 +779,6 @@ getpriority(int which /* ignored */, int
 int emx_runtime_init;			/* If 1, we need to manually init it */
 int emx_exception_init;			/* If 1, we need to manually set it */
 
-/* There is no big sense to make it thread-specific, since signals 
-   are delivered to thread 1 only.  XXXX Maybe make it into an array? */
-static int spawn_pid;
-static int spawn_killed;
 
 static Signal_t
 spawn_sighandler(int sig)
@@ -706,6 +862,20 @@ my_type()
     return (pib->pib_ultype);
 }
 
+static void
+my_type_set(int type)
+{
+    int rc;
+    TIB *tib;
+    PIB *pib;
+    
+    if (!(_emx_env & 0x200))
+	Perl_croak_nocontext("Can't set type on DOS"); /* not OS/2. */
+    if (CheckOSError(DosGetInfoBlocks(&tib, &pib))) 
+	Perl_croak_nocontext("Error getting info blocks");
+    pib->pib_ultype = type;
+}
+
 static ULONG
 file_type(char *path)
 {
@@ -730,8 +900,6 @@ file_type(char *path)
     return apptype;
 }
 
-static ULONG os2_mytype;
-
 /* Spawn/exec a program, revert to shell if needed. */
 /* global PL_Argv[] contains arguments. */
 
@@ -745,11 +913,11 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, 
 {
 	int trueflag = flag;
 	int rc, pass = 1;
-	char *tmps;
-	char *args[4];
-	static char * fargs[4] 
+	char *real_name;
+	char const * args[4];
+	static const char * const fargs[4] 
 	    = { "/bin/sh", "-c", "\"$@\"", "spawn-via-shell", };
-	char **argsp = fargs;
+	const char * const *argsp = fargs;
 	int nargs = 4;
 	int force_shell;
  	int new_stderr = -1, nostderr = 0;
@@ -760,24 +928,26 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, 
 	
 	if (flag == P_WAIT)
 		flag = P_NOWAIT;
+	if (really && !*(real_name = SvPV(really, n_a)))
+	    really = Nullsv;
 
       retry:
 	if (strEQ(PL_Argv[0],"/bin/sh")) 
 	    PL_Argv[0] = PL_sh_path;
 
 	/* We should check PERL_SH* and PERLLIB_* as well? */
-	if (!really || !*(tmps = SvPV(really, n_a)))
-	    tmps = PL_Argv[0];
-	if (tmps[0] != '/' && tmps[0] != '\\'
-	    && !(tmps[0] && tmps[1] == ':' 
-		 && (tmps[2] == '/' || tmps[2] != '\\'))
+	if (!really || pass >= 2)
+	    real_name = PL_Argv[0];
+	if (real_name[0] != '/' && real_name[0] != '\\'
+	    && !(real_name[0] && real_name[1] == ':' 
+		 && (real_name[2] == '/' || real_name[2] != '\\'))
 	    ) /* will spawnvp use PATH? */
 	    TAINT_ENV();	/* testing IFS here is overkill, probably */
 
       reread:
 	force_shell = 0;
 	if (_emx_env & 0x200) { /* OS/2. */ 
-	    int type = file_type(tmps);
+	    int type = file_type(real_name);
 	  type_again:
 	    if (type == -1) {		/* Not found */
 		errno = ENOENT;
@@ -792,10 +962,10 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, 
 	    else if (type == -3) {		/* Is a directory? */
 		/* Special-case this */
 		char tbuf[512];
-		int l = strlen(tmps);
+		int l = strlen(real_name);
 
 		if (l + 5 <= sizeof tbuf) {
-		    strcpy(tbuf, tmps);
+		    strcpy(tbuf, real_name);
 		    strcpy(tbuf + l, ".exe");
 		    type = file_type(tbuf);
 		    if (type >= -3)
@@ -809,11 +979,11 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, 
 	    switch (type & 7) {
 		/* Ignore WINDOWCOMPAT and FAPI, start them the same type we are. */
 	    case FAPPTYP_WINDOWAPI: 
-	    {
+	    {	/* Apparently, kids are started basing on startup type, not the morphed type */
 		if (os2_mytype != 3) {	/* not PM */
 		    if (flag == P_NOWAIT)
 			flag = P_PM;
-		    else if ((flag & 7) != P_PM && (flag & 7) != P_SESSION)
+		    else if ((flag & 7) != P_PM && (flag & 7) != P_SESSION && ckWARN(WARN_EXEC))
 			Perl_warner(aTHX_ packWARN(WARN_EXEC), "Starting PM process with flag=%d, mytype=%d",
 			     flag, os2_mytype);
 		}
@@ -824,7 +994,7 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, 
 		if (os2_mytype != 0) {	/* not full screen */
 		    if (flag == P_NOWAIT)
 			flag = P_SESSION;
-		    else if ((flag & 7) != P_SESSION)
+		    else if ((flag & 7) != P_SESSION && ckWARN(WARN_EXEC))
 			Perl_warner(aTHX_ packWARN(WARN_EXEC), "Starting Full Screen process with flag=%d, mytype=%d",
 			     flag, os2_mytype);
 		}
@@ -859,24 +1029,23 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, 
 	}
 
 #if 0
-	rc = result(aTHX_ trueflag, spawnvp(flag,tmps,PL_Argv));
+	rc = result(aTHX_ trueflag, spawnvp(flag,real_name,PL_Argv));
 #else
 	if (execf == EXECF_TRUEEXEC)
-	    rc = execvp(tmps,PL_Argv);
+	    rc = execvp(real_name,PL_Argv);
 	else if (execf == EXECF_EXEC)
-	    rc = spawnvp(trueflag | P_OVERLAY,tmps,PL_Argv);
+	    rc = spawnvp(trueflag | P_OVERLAY,real_name,PL_Argv);
 	else if (execf == EXECF_SPAWN_NOWAIT)
-	    rc = spawnvp(flag,tmps,PL_Argv);
+	    rc = spawnvp(flag,real_name,PL_Argv);
         else if (execf == EXECF_SYNC)
-	    rc = spawnvp(trueflag,tmps,PL_Argv);
+	    rc = spawnvp(trueflag,real_name,PL_Argv);
         else				/* EXECF_SPAWN, EXECF_SPAWN_BYFLAG */
 	    rc = result(aTHX_ trueflag, 
-			spawnvp(flag,tmps,PL_Argv));
+			spawnvp(flag,real_name,PL_Argv));
 #endif 
-	if (rc < 0 && pass == 1
-	    && (tmps == PL_Argv[0])) { /* Cannot transfer `really' via shell. */
+	if (rc < 0 && pass == 1) {
 	      do_script:
-	    {
+	  if (real_name == PL_Argv[0]) {
 	    int err = errno;
 
 	    if (err == ENOENT || err == ENOEXEC) {
@@ -912,7 +1081,7 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, 
 	                scr = SvPV(scrsv, n_a);	/* Reload */
 			if (PerlLIO_stat(scr,&PL_statbuf) >= 0
 			    && !S_ISDIR(PL_statbuf.st_mode)) {	/* Found */
-				tmps = scr;
+				real_name = scr;
 				pass++;
 				goto reread;
 			} else {		/* Restore */
@@ -922,7 +1091,8 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, 
 		    }
 		    if (PerlIO_close(file) != 0) { /* Failure */
 		      panic_file:
-			Perl_warner(aTHX_ packWARN(WARN_EXEC), "Error reading \"%s\": %s", 
+			if (ckWARN(WARN_EXEC))
+			   Perl_warner(aTHX_ packWARN(WARN_EXEC), "Error reading \"%s\": %s", 
 			     scr, Strerror(errno));
 			buf = "";	/* Not #! */
 			goto doshell_args;
@@ -975,7 +1145,7 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, 
 		  doshell_args:
 		    {
 			char **a = PL_Argv;
-			char *exec_args[2];
+			const char *exec_args[2];
 
 			if (force_shell 
 			    || (!buf[0] && file)) { /* File without magic */
@@ -1046,8 +1216,8 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, 
 						   long enough. */
 			    a--;
 			}
-			while (--nargs >= 0)
-			    PL_Argv[nargs] = argsp[nargs];
+			while (--nargs >= 0) /* XXXX Discard const... */
+			    PL_Argv[nargs] = (char*)argsp[nargs];
 			/* Enable pathless exec if #! (as pdksh). */
 			pass = (buf[0] == '#' ? 2 : 3);
 			goto retry;
@@ -1056,6 +1226,20 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, 
 		/* Not found: restore errno */
 		errno = err;
 	    }
+	  } else if (errno == ENOEXEC) { /* Cannot transfer `real_name' via shell. */
+		if (rc < 0 && ckWARN(WARN_EXEC))
+		    Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s script `%s' with ARGV[0] being `%s'", 
+			 ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC) 
+			  ? "spawn" : "exec"),
+			 real_name, PL_Argv[0]);
+		goto warned;
+	  } else if (errno == ENOENT) { /* Cannot transfer `real_name' via shell. */
+		if (rc < 0 && ckWARN(WARN_EXEC))
+		    Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s `%s' with ARGV[0] being `%s' (looking for executables only, not found)", 
+			 ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC) 
+			  ? "spawn" : "exec"),
+			 real_name, PL_Argv[0]);
+		goto warned;
 	  }
 	} else if (rc < 0 && pass == 2 && errno == ENOENT) { /* File not found */
 	    char *no_dir = strrchr(PL_Argv[0], '/');
@@ -1072,7 +1256,8 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, 
 	    Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s\n", 
 		 ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC) 
 		  ? "spawn" : "exec"),
-		 PL_Argv[0], Strerror(errno));
+		 real_name, Strerror(errno));
+      warned:
 	if (rc < 0 && (execf != EXECF_SPAWN_NOWAIT) 
 	    && ((trueflag & 0xFF) == P_WAIT)) 
 	    rc = -1;
@@ -1215,9 +1400,9 @@ do_spawn3(pTHX_ char *cmd, int execf, in
     return rc;
 }
 
-/* Array spawn.  */
+/* Array spawn/exec.  */
 int
-os2_do_aspawn(pTHX_ SV *really, register void **vmark, register void **vsp)
+os2_aspawn4(pTHX_ SV *really, register SV **vmark, register SV **vsp, int execing)
 {
     register SV **mark = (SV **)vmark;
     register SV **sp = (SV **)vsp;
@@ -1245,16 +1430,32 @@ os2_do_aspawn(pTHX_ SV *really, register
 	}
 	*a = Nullch;
 
-	if (flag_set && (a == PL_Argv + 1)) { /* One arg? */
+	if ( flag_set && (a == PL_Argv + 1)
+	     && !really && !execing ) { 		/* One arg? */
 	    rc = do_spawn3(aTHX_ a[-1], EXECF_SPAWN_BYFLAG, flag);
 	} else
-	    rc = do_spawn_ve(aTHX_ really, flag, EXECF_SPAWN, NULL, 0);
+	    rc = do_spawn_ve(aTHX_ really, flag,
+			     (execing ? EXECF_EXEC : EXECF_SPAWN), NULL, 0);
     } else
     	rc = -1;
     do_execfree();
     return rc;
 }
 
+/* Array spawn.  */
+int
+os2_do_aspawn(pTHX_ SV *really, register SV **vmark, register SV **vsp)
+{
+    return os2_aspawn4(aTHX_ really, vmark, vsp, 0);
+}
+
+/* Array exec.  */
+bool
+Perl_do_aexec(pTHX_ SV* really, SV** vmark, SV** vsp)
+{
+    return os2_aspawn4(aTHX_ really, vmark, vsp, 1);
+}
+
 int
 os2_do_spawn(pTHX_ char *cmd)
 {
@@ -1460,7 +1661,9 @@ os2_stat(const char *name, struct stat *
 
     memset(st, 0, sizeof *st);
     st->st_mode = S_IFCHR|0666;
+    MUTEX_LOCK(&perlos2_state_mutex);
     st->st_ino = (ino-- & 0x7FFF);
+    MUTEX_UNLOCK(&perlos2_state_mutex);
     st->st_nlink = 1;
     return 0;
 }
@@ -1583,7 +1786,6 @@ XS(XS_File__Copy_syscopy)
 char *
 mod2fname(pTHX_ SV *sv)
 {
-    static char fname[9];
     int pos = 6, len, avlen;
     unsigned int sum = 0;
     char *s;
@@ -1652,7 +1854,6 @@ char *
 os2error(int rc)
 {
 	dTHX;
-	static char buf[300];
 	ULONG len;
 	char *s;
 	int number = SvTRUE(get_sv("OS2::nsyserror", TRUE));
@@ -1661,17 +1862,37 @@ os2error(int rc)
 	if (rc == 0)
 		return "";
 	if (number) {
-	    sprintf(buf, "SYS%04d=%#x: ", rc, rc);
-	    s = buf + strlen(buf);
+	    sprintf(os2error_buf, "SYS%04d=%#x: ", rc, rc);
+	    s = os2error_buf + strlen(os2error_buf);
 	} else
-	    s = buf;
-	if (DosGetMessage(NULL, 0, s, sizeof(buf) - 1 - (s-buf), 
+	    s = os2error_buf;
+	if (DosGetMessage(NULL, 0, s, sizeof(os2error_buf) - 1 - (s-os2error_buf), 
 			  rc, "OSO001.MSG", &len)) {
+	    char *name = "";
+
 	    if (!number) {
-		sprintf(buf, "SYS%04d=%#x: ", rc, rc);
-		s = buf + strlen(buf);
+		sprintf(os2error_buf, "SYS%04d=%#x: ", rc, rc);
+		s = os2error_buf + strlen(os2error_buf);
+	    }
+	    switch (rc) {
+	    case PMERR_INVALID_HWND:
+		name = "PMERR_INVALID_HWND";
+		break;
+	    case PMERR_INVALID_HMQ:
+		name = "PMERR_INVALID_HMQ";
+		break;
+	    case PMERR_CALL_FROM_WRONG_THREAD:
+		name = "PMERR_CALL_FROM_WRONG_THREAD";
+		break;
+	    case PMERR_NO_MSG_QUEUE:
+		name = "PMERR_NO_MSG_QUEUE";
+		break;
+	    case PMERR_NOT_IN_A_PM_SESSION:
+		name = "PMERR_NOT_IN_A_PM_SESSION";
+		break;
 	    }
-	    sprintf(s, "[No description found in OSO001.MSG]");
+	    sprintf(s, "%s%s[No description found in OSO001.MSG]", 
+		    name, (*name ? "=" : ""));
 	} else {
 		s[len] = '\0';
 		if (len && s[len - 1] == '\n')
@@ -1680,12 +1901,12 @@ os2error(int rc)
 			s[--len] = 0;
 		if (len && s[len - 1] == '.')
 			s[--len] = 0;
-		if (len >= 10 && number && strnEQ(s, buf, 7)
+		if (len >= 10 && number && strnEQ(s, os2error_buf, 7)
 		    && s[7] == ':' && s[8] == ' ')
 		    /* Some messages start with SYSdddd:, some not */
 		    Move(s + 9, s, (len -= 9) + 1, char);
 	}
-	return buf;
+	return os2error_buf;
 }
 
 void
@@ -1741,10 +1962,6 @@ os2_execname(pTHX)
 char *
 perllib_mangle(char *s, unsigned int l)
 {
-    static char *newp, *oldp;
-    static int newl, oldl, notfound;
-    static char ret[STATIC_FILE_LENGTH+1];
-    
     if (!newp && !notfound) {
 	newp = getenv("PERLLIB_PREFIX");
 	if (newp) {
@@ -1761,8 +1978,8 @@ perllib_mangle(char *s, unsigned int l)
 	    if (newl == 0 || oldl == 0) {
 		Perl_croak_nocontext("Malformed PERLLIB_PREFIX");
 	    }
-	    strcpy(ret, newp);
-	    s = ret;
+	    strcpy(mangle_ret, newp);
+	    s = mangle_ret;
 	    while (*s) {
 		if (*s == '\\') *s = '/';
 		s++;
@@ -1783,8 +2000,8 @@ perllib_mangle(char *s, unsigned int l)
     if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH) {
 	Perl_croak_nocontext("Malformed PERLLIB_PREFIX");
     }
-    strcpy(ret + newl, s + oldl);
-    return ret;
+    strcpy(mangle_ret + newl, s + oldl);
+    return mangle_ret;
 }
 
 unsigned long 
@@ -1793,6 +2010,31 @@ Perl_hab_GET()			/* Needed if perl.h can
     return perl_hab_GET();
 }
 
+static void
+Create_HMQ(int serve, char *message)	/* Assumes morphing */
+{
+    unsigned fpflag = _control87(0,0);
+
+    init_PMWIN_entries();
+    /* 64 messages if before OS/2 3.0, ignored otherwise */
+    Perl_hmq = (*PMWIN_entries.CreateMsgQueue)(perl_hab_GET(), 64);
+    if (!Perl_hmq) {
+	dTHX;
+
+	SAVEINT(rmq_cnt);		/* Allow catch()ing. */
+	if (rmq_cnt++)
+	    _exit(188);		/* Panic can try to create a window. */
+	CroakWinError(1, message ? message : "Cannot create a message queue");
+    }
+    if (serve != -1)
+	(*PMWIN_entries.CancelShutdown)(Perl_hmq, !serve);
+    /* We may have loaded some modules */
+    _control87(fpflag, MCW_EM); /* Some modules reset FP flags on (un)load */
+}
+
+#define REGISTERMQ_WILL_SERVE		1
+#define REGISTERMQ_IMEDIATE_UNMORPH	2
+
 HMQ
 Perl_Register_MQ(int serve)
 {
@@ -1802,24 +2044,20 @@ Perl_Register_MQ(int serve)
 
     Perl_hmq_refcnt = 0;		/* Be extra safe */
     DosGetInfoBlocks(&tib, &pib);
-    Perl_os2_initial_mode = pib->pib_ultype;
-    /* Try morphing into a PM application. */
-    if (pib->pib_ultype != 3)		/* 2 is VIO */
-	pib->pib_ultype = 3;		/* 3 is PM */
-    init_PMWIN_entries();
-    /* 64 messages if before OS/2 3.0, ignored otherwise */
-    Perl_hmq = (*PMWIN_entries.CreateMsgQueue)(perl_hab_GET(), 64); 
-    if (!Perl_hmq) {
-        dTHX;
-	static int cnt;
-
-	SAVEINT(cnt);			/* Allow catch()ing. */
-	if (cnt++)
-	    _exit(188);			/* Panic can try to create a window. */
-	Perl_croak_nocontext("Cannot create a message queue, or morph to a PM application");
+    if (!Perl_morph_refcnt) {    
+	Perl_os2_initial_mode = pib->pib_ultype;
+	/* Try morphing into a PM application. */
+	if (pib->pib_ultype != 3)		/* 2 is VIO */
+	    pib->pib_ultype = 3;		/* 3 is PM */	
+    }
+    Create_HMQ(-1,			/* We do CancelShutdown ourselves */
+	       "Cannot create a message queue, or morph to a PM application");
+    if ((serve & REGISTERMQ_IMEDIATE_UNMORPH)) {
+	if (!Perl_morph_refcnt && Perl_os2_initial_mode != 3)
+	    pib->pib_ultype = Perl_os2_initial_mode;
     }
   }
-    if (serve) {
+    if (serve & REGISTERMQ_WILL_SERVE) {
 	if ( Perl_hmq_servers <= 0	/* Safe to inform us on shutdown, */
 	     && Perl_hmq_refcnt > 0 )	/* this was switched off before... */
 	    (*PMWIN_entries.CancelShutdown)(Perl_hmq, 0);
@@ -1827,6 +2065,8 @@ Perl_Register_MQ(int serve)
     } else if (!Perl_hmq_servers)	/* Do not inform us on shutdown */
 	(*PMWIN_entries.CancelShutdown)(Perl_hmq, 1);
     Perl_hmq_refcnt++;
+    if (!(serve & REGISTERMQ_IMEDIATE_UNMORPH))
+	Perl_morph_refcnt++;
     return Perl_hmq;
 }
 
@@ -1873,24 +2113,31 @@ Perl_Process_Messages(int force, I32 *cn
 void
 Perl_Deregister_MQ(int serve)
 {
-    PPIB pib;
-    PTIB tib;
-
-    if (serve)
+    if (serve & REGISTERMQ_WILL_SERVE)
 	Perl_hmq_servers--;
+
     if (--Perl_hmq_refcnt <= 0) {
+	unsigned fpflag = _control87(0,0);
+
 	init_PMWIN_entries();			/* To be extra safe */
 	(*PMWIN_entries.DestroyMsgQueue)(Perl_hmq);
 	Perl_hmq = 0;
+	/* We may have (un)loaded some modules */
+	_control87(fpflag, MCW_EM); /* Some modules reset FP flags on (un)load */
+    } else if ((serve & REGISTERMQ_WILL_SERVE) && Perl_hmq_servers <= 0)
+	(*PMWIN_entries.CancelShutdown)(Perl_hmq, 1); /* Last server exited */
+    if (!(serve & REGISTERMQ_IMEDIATE_UNMORPH) && (--Perl_morph_refcnt <= 0)) {
 	/* Try morphing back from a PM application. */
+	PPIB pib;
+	PTIB tib;
+
 	DosGetInfoBlocks(&tib, &pib);
 	if (pib->pib_ultype == 3)		/* 3 is PM */
 	    pib->pib_ultype = Perl_os2_initial_mode;
 	else
 	    Perl_warn_nocontext("Unexpected program mode %d when morphing back from PM",
-		 pib->pib_ultype);
-    } else if (serve && Perl_hmq_servers <= 0)	/* Last server exited */
-	(*PMWIN_entries.CancelShutdown)(Perl_hmq, 1);
+				pib->pib_ultype);
+    }
 }
 
 #define sys_is_absolute(path) ( isALPHA((path)[0]) && (path)[1] == ':' \
@@ -1903,8 +2150,6 @@ Perl_Deregister_MQ(int serve)
 #define sys_chdir(p) (chdir(p) == 0)
 #define change_drive(d) (_chdrive(d), (current_drive() == toupper(d)))
 
-static int DOS_harderr_state = -1;    
-
 XS(XS_OS2_Error)
 {
     dXSARGS;
@@ -1928,8 +2173,6 @@ XS(XS_OS2_Error)
     XSRETURN(1);
 }
 
-static signed char DOS_suppression_state = -1;    
-
 XS(XS_OS2_Errors2Drive)
 {
     dXSARGS;
@@ -2445,7 +2688,8 @@ DeclOSFuncByORD(APIRET, _DosQueryModFrom
 			ULONG * Offset, ULONG Address),
 			(hmod, obj, BufLen, Buf, Offset, Address))
 
-enum module_name_how { mod_name_handle, mod_name_shortname, mod_name_full};
+enum module_name_how { mod_name_handle, mod_name_shortname, mod_name_full,
+  mod_name_C_function = 0x100, mod_name_HMODULE = 0x200};
 
 static SV*
 module_name_at(void *pp, enum module_name_how how)
@@ -2454,14 +2698,19 @@ module_name_at(void *pp, enum module_nam
     char buf[MAXPATHLEN];
     char *p = buf;
     HMODULE mod;
-    ULONG obj, offset, rc;
+    ULONG obj, offset, rc, addr = (ULONG)pp;
 
-    if (!_DosQueryModFromEIP(&mod, &obj, sizeof(buf), buf, &offset, (ULONG)pp))
+    if (how & mod_name_HMODULE) {
+	if ((how & ~mod_name_HMODULE) == mod_name_shortname)
+	    Perl_croak(aTHX_ "Can't get short module name from a handle");
+	mod = (HMODULE)pp;
+	how &= ~mod_name_HMODULE;
+    } else if (!_DosQueryModFromEIP(&mod, &obj, sizeof(buf), buf, &offset, addr))
 	return &PL_sv_undef;
     if (how == mod_name_handle)
 	return newSVuv(mod);
     /* Full name... */
-    if ( how == mod_name_full
+    if ( how != mod_name_shortname
 	 && CheckOSError(DosQueryModuleName(mod, sizeof(buf), buf)) )
 	return &PL_sv_undef;
     while (*p) {
@@ -2478,6 +2727,10 @@ module_name_of_cv(SV *cv, enum module_na
     if (!cv || !SvROK(cv) || SvTYPE(SvRV(cv)) != SVt_PVCV || !CvXSUB(SvRV(cv))) {
 	dTHX;
 
+	if (how & mod_name_C_function)
+	    return module_name_at((void*)SvIV(cv), how & ~mod_name_C_function);
+	else if (how & mod_name_HMODULE)
+	    return module_name_at((void*)SvIV(cv), how);
 	Perl_croak(aTHX_ "Not an XSUB reference");
     }
     return module_name_at(CvXSUB(SvRV(cv)), how);
@@ -2510,6 +2763,70 @@ XS(XS_OS2_DLLname)
     XSRETURN(1);
 }
 
+DeclOSFuncByORD(INT, _Dos32QueryHeaderInfo, ORD_Dos32QueryHeaderInfo,
+			(ULONG r1, ULONG r2, PVOID buf, ULONG szbuf, ULONG fnum),
+			(r1, r2, buf, szbuf, fnum))
+
+XS(XS_OS2__headerInfo)
+{
+    dXSARGS;
+    if (items > 4 || items < 2)
+	Perl_croak(aTHX_ "Usage: OS2::_headerInfo(req,size[,handle,[offset]])");
+    {
+	ULONG	req = (ULONG)SvIV(ST(0));
+	STRLEN	size = (STRLEN)SvIV(ST(1)), n_a;
+	ULONG	handle = (items >= 3 ? (ULONG)SvIV(ST(2)) : 0);
+	ULONG	offset = (items >= 4 ? (ULONG)SvIV(ST(3)) : 0);
+
+	if (size <= 0)
+	    Perl_croak(aTHX_ "OS2::_headerInfo(): unexpected size: %d", (int)size);
+	ST(0) = newSVpvn("",0);
+	SvGROW(ST(0), size + 1);
+	sv_2mortal(ST(0));
+
+	if (!_Dos32QueryHeaderInfo(handle, offset, SvPV(ST(0), n_a), size, req)) 
+	    Perl_croak(aTHX_ "OS2::_headerInfo(%ld,%ld,%ld,%ld) error: %s",
+		       req, size, handle, offset, os2error(Perl_rc));
+	SvCUR_set(ST(0), size);
+	*SvEND(ST(0)) = 0;
+    }
+    XSRETURN(1);
+}
+
+#define DQHI_QUERYLIBPATHSIZE      4
+#define DQHI_QUERYLIBPATH          5
+
+XS(XS_OS2_libPath)
+{
+    dXSARGS;
+    if (items != 0)
+	Perl_croak(aTHX_ "Usage: OS2::libPath()");
+    {
+	ULONG	size;
+	STRLEN	n_a;
+
+	if (!_Dos32QueryHeaderInfo(0, 0, &size, sizeof(size), 
+				   DQHI_QUERYLIBPATHSIZE)) 
+	    Perl_croak(aTHX_ "OS2::_headerInfo(%ld,%ld,%ld,%ld) error: %s",
+		       DQHI_QUERYLIBPATHSIZE, sizeof(size), 0, 0,
+		       os2error(Perl_rc));
+	ST(0) = newSVpvn("",0);
+	SvGROW(ST(0), size + 1);
+	sv_2mortal(ST(0));
+
+	/* We should be careful: apparently, this entry point does not
+	   pay attention to the size argument, so may overwrite
+	   unrelated data! */
+	if (!_Dos32QueryHeaderInfo(0, 0, SvPV(ST(0), n_a), size,
+				   DQHI_QUERYLIBPATH)) 
+	    Perl_croak(aTHX_ "OS2::_headerInfo(%ld,%ld,%ld,%ld) error: %s",
+		       DQHI_QUERYLIBPATH, size, 0, 0, os2error(Perl_rc));
+	SvCUR_set(ST(0), size);
+	*SvEND(ST(0)) = 0;
+    }
+    XSRETURN(1);
+}
+
 #define get_control87()		_control87(0,0)
 #define set_control87		_control87
 
@@ -2530,6 +2847,55 @@ XS(XS_OS2__control87)
     XSRETURN(1);
 }
 
+XS(XS_OS2_mytype)
+{
+    dXSARGS;
+    int which = 0;
+
+    if (items < 0 || items > 1)
+	Perl_croak(aTHX_ "Usage: OS2::mytype([which])");
+    if (items == 1)
+	which = (int)SvIV(ST(0));
+    {
+	unsigned	RETVAL;
+
+	switch (which) {
+	case 0:
+	    RETVAL = os2_mytype;	/* Reset after fork */
+	    break;
+	case 1:
+	    RETVAL = os2_mytype_ini;	/* Before any fork */
+	    break;
+	case 2:
+	    RETVAL = Perl_os2_initial_mode;	/* Before first morphing */
+	    break;
+	case 3:
+	    RETVAL = my_type();		/* Morphed type */
+	    break;
+	default:
+	    Perl_croak(aTHX_ "OS2::mytype(which): unknown which=%d", which);
+	}
+	ST(0) = sv_newmortal();
+	sv_setiv(ST(0), (IV)RETVAL);
+    }
+    XSRETURN(1);
+}
+
+
+XS(XS_OS2_mytype_set)
+{
+    dXSARGS;
+    int type;
+
+    if (items == 1)
+	type = (int)SvIV(ST(0));
+    else
+	Perl_croak(aTHX_ "Usage: OS2::mytype_set(type)");
+    my_type_set(type);
+    XSRETURN_EMPTY;
+}
+
+
 XS(XS_OS2_get_control87)
 {
     dXSARGS;
@@ -2608,6 +2974,10 @@ Xs_OS2_init(pTHX)
         newXSproto("OS2::get_control87", XS_OS2_get_control87, file, "");
         newXSproto("OS2::set_control87", XS_OS2_set_control87, file, ";$$");
         newXSproto("OS2::DLLname", XS_OS2_DLLname, file, ";$$");
+        newXSproto("OS2::mytype", XS_OS2_mytype, file, ";$");
+        newXSproto("OS2::mytype_set", XS_OS2_mytype_set, file, "$");
+        newXSproto("OS2::_headerInfo", XS_OS2__headerInfo, file, "$$;$$");
+        newXSproto("OS2::libPath", XS_OS2_libPath, file, "");
 	gv = gv_fetchpv("OS2::is_aout", TRUE, SVt_PV);
 	GvMULTI_on(gv);
 #ifdef PERL_IS_AOUT
@@ -2645,7 +3015,7 @@ static void jmp_out_of_atexit(void);
 
 static void
 my_emx_init(void *layout) {
-    static volatile void *p = 0;	/* Cannot be on stack! */
+    static volatile void *old_esp = 0;	/* Cannot be on stack! */
 
     /* Can't just call emx_init(), since it moves the stack pointer */
     /* It also busts a lot of registers, so be extra careful */
@@ -2656,7 +3026,7 @@ my_emx_init(void *layout) {
 		"call __emx_init\n"
 		"movl %1, %%esp\n"
 		"popa\n"
-		"popf\n" : : "r" (layout), "m" (p)	);
+		"popf\n" : : "r" (layout), "m" (old_esp)	);
 }
 
 struct layout_table_t {
@@ -2680,7 +3050,7 @@ struct layout_table_t {
 
 static ULONG
 my_os_version() {
-    static ULONG res;			/* Cannot be on stack! */
+    static ULONG osv_res;		/* Cannot be on stack! */
 
     /* Can't just call __os_version(), since it does not follow C
        calling convention: it busts a lot of registers, so be extra careful */
@@ -2689,9 +3059,9 @@ my_os_version() {
 		"call ___os_version\n"
 		"movl %%eax, %0\n"
 		"popa\n"
-		"popf\n" : "=m" (res)	);
+		"popf\n" : "=m" (osv_res)	);
 
-    return res;
+    return osv_res;
 }
 
 static void
@@ -2703,7 +3073,6 @@ force_init_emx_runtime(EXCEPTIONREGISTRA
     void *oldstackend, *oldstack;
     PPIB pib;
     PTIB tib;
-    static ULONG os2_dll;
     ULONG rc, error = 0, out;
     char buf[512];
     static struct layout_table_t layout_table;
@@ -2714,7 +3083,7 @@ force_init_emx_runtime(EXCEPTIONREGISTRA
     } *newstack;
     char *s;
 
-    layout_table.os2_dll = (ULONG)&os2_dll;
+    layout_table.os2_dll = (ULONG)&os2_dll_fake;
     layout_table.flags   = 0x02000002;	/* flags: application, OMF */
 
     DosGetInfoBlocks(&tib, &pib);
@@ -2847,12 +3216,12 @@ Perl_OS2_term(void **p, int exitstatus, 
 
 extern ULONG __os_version();		/* See system.doc */
 
-static int emx_wasnt_initialized;
-
 void
 check_emx_runtime(char **env, EXCEPTIONREGISTRATIONRECORD *preg)
 {
-    ULONG v_crt, v_emx;
+    ULONG v_crt, v_emx, count = 0, rc, rc1, maybe_inited = 0;
+    static HMTX hmtx_emx_init = NULLHANDLE;
+    static int emx_init_done = 0;
 
     /*  If _environ is not set, this code sits in a DLL which
 	uses a CRT DLL which not compatible with the executable's
@@ -2861,6 +3230,44 @@ check_emx_runtime(char **env, EXCEPTIONR
     if (_environ != NULL)
 	return;				/* Properly initialized */
 
+    /* It is not DOS, so we may use OS/2 API now */
+    /* Some data we manipulate is static; protect ourselves from
+       calling the same API from a different thread. */
+    DosEnterMustComplete(&count);
+
+    rc1 = DosEnterCritSec();
+    if (!hmtx_emx_init)
+	rc = DosCreateMutexSem(NULL, &hmtx_emx_init, 0, TRUE); /*Create owned*/
+    else
+	maybe_inited = 1;
+
+    if (rc != NO_ERROR)
+	hmtx_emx_init = NULLHANDLE;
+
+    if (rc1 == NO_ERROR)
+	DosExitCritSec();
+    DosExitMustComplete(&count);
+
+    while (maybe_inited) { /* Other thread did or is doing the same now */
+	if (emx_init_done)
+	    return;
+	rc = DosRequestMutexSem(hmtx_emx_init,
+				(ULONG) SEM_INDEFINITE_WAIT);  /* Timeout (none) */
+	if (rc == ERROR_INTERRUPT)
+	    continue;
+	if (rc != NO_ERROR) {
+	    char buf[80];
+	    ULONG out;
+
+	    sprintf(buf,
+		    "panic: EMX backdoor init: DosRequestMutexSem error: %lu=%#lx\n", rc, rc);	    
+	    DosWrite(2, buf, strlen(buf), &out);
+	    return;
+	}
+	DosReleaseMutexSem(hmtx_emx_init);
+	return;
+    }
+
     /*  If the executable does not use EMX.DLL, EMX.DLL is not completely
 	initialized either.  Uninitialized EMX.DLL returns 0 in the low
 	nibble of __os_version().  */
@@ -2913,6 +3320,9 @@ check_emx_runtime(char **env, EXCEPTIONR
 	*ep = NULL;
     }
     _environ = _org_environ = env;
+    emx_init_done = 1;
+    if (hmtx_emx_init)
+	DosReleaseMutexSem(hmtx_emx_init);
 }
 
 #define ENTRY_POINT 0x10000
@@ -2973,8 +3383,11 @@ Perl_OS2_init3(char **env, void **preg, 
     }
 #if defined(USE_5005THREADS) || defined(USE_ITHREADS)
     MUTEX_INIT(&start_thread_mutex);
+    MUTEX_INIT(&perlos2_state_mutex);
 #endif
     os2_mytype = my_type();		/* Do it before morphing.  Needed? */
+    os2_mytype_ini = os2_mytype;
+    Perl_os2_initial_mode = -1;		/* Uninit */
     /* Some DLLs reset FP flags on load.  We may have been linked with them */
     _control87(MCW_EM, MCW_EM);
 }
@@ -3072,16 +3485,20 @@ my_flock(int handle, int o)
   ULONG         timeout, handle_type, flag_word;
   APIRET        rc;
   int           blocking, shared;
-  static int	use_my = -1;
+  static int	use_my_flock = -1;
 
-  if (use_my == -1) {
+  if (use_my_flock == -1) {
+   MUTEX_LOCK(&perlos2_state_mutex);
+   if (use_my_flock == -1) {
     char *s = getenv("USE_PERL_FLOCK");
     if (s)
-	use_my = atoi(s);
+	use_my_flock = atoi(s);
     else 
-	use_my = 1;
+	use_my_flock = 1;
+   }
+   MUTEX_UNLOCK(&perlos2_state_mutex);
   }
-  if (!(_emx_env & 0x200) || !use_my) 
+  if (!(_emx_env & 0x200) || !use_my_flock) 
     return flock(handle, o);	/* Delegate to EMX. */
   
                                         /* is this a file? */
@@ -3175,9 +3592,6 @@ my_flock(int handle, int o)
   return 0;
 }
 
-static int pwent_cnt;
-static int _my_pwent = -1;
-
 static int
 use_my_pwent(void)
 {
@@ -3224,8 +3638,6 @@ my_getpwent (void)
   return getpwuid(0);
 }
 
-static int grent_cnt;
-
 void
 setgrent(void)
 {
@@ -3254,7 +3666,6 @@ static const char pw_p[] = "Jf0Wb/BzMFvk
 static struct passwd *
 passw_wrap(struct passwd *p)
 {
-    static struct passwd pw;
     char *s;
 
     if (!p || (p->pw_passwd && *p->pw_passwd)) /* Not a dangerous password */
@@ -3283,6 +3694,21 @@ my_getpwnam (__const__ char *n)
 char *
 gcvt_os2 (double value, int digits, char *buffer)
 {
+  double absv = value > 0 ? value : -value;
+  /* EMX implementation is lousy between 0.1 and 0.0001 (uses exponents below
+     0.1), 1-digit stuff is ok below 0.001; multi-digit below 0.0001. */
+  int buggy;
+
+  absv *= 10000;
+  buggy = (absv < 1000 && (absv >= 10 || (absv > 1 && floor(absv) != absv)));
+  
+  if (buggy) {
+    char pat[12];
+
+    sprintf(pat, "%%.%dg", digits);
+    sprintf(buffer, pat, value);
+    return buffer;
+  }
   return gcvt (value, digits, buffer);
 }
 
@@ -3293,14 +3719,66 @@ int fork_with_resources()
   dTHX;
   void *ctx = PERL_GET_CONTEXT;
 #endif
-
+  unsigned fpflag = _control87(0,0);
   int rc = fork();
 
-#if (defined(USE_5005THREADS) || defined(USE_ITHREADS)) && !defined(USE_SLOW_THREAD_SPECIFIC)
   if (rc == 0) {			/* child */
+#if (defined(USE_5005THREADS) || defined(USE_ITHREADS)) && !defined(USE_SLOW_THREAD_SPECIFIC)
     ALLOC_THREAD_KEY;			/* Acquire the thread-local memory */
     PERL_SET_CONTEXT(ctx);		/* Reinit the thread-local memory */
-  }
 #endif
+    
+    {					/* Reload loaded-on-demand DLLs */
+	struct dll_handle_t *dlls = dll_handles;
+
+	while (dlls->modname) {
+	    char dllname[260], fail[260];
+	    ULONG rc;
+
+	    if (!dlls->handle) {	/* Was not loaded */
+		dlls++;
+		continue;
+	    }
+	    /* It was loaded in the parent.  We need to reload it. */
+
+	    rc = DosQueryModuleName(dlls->handle, sizeof(dllname), dllname);
+	    if (rc) {
+		Perl_warn_nocontext("Can't find DLL name for the module `%s' by the handle %d, rc=%lu=%#lx",
+				    dlls->modname, (int)dlls->handle, rc, rc);
+		dlls++;
+		continue;
+	    }
+	    rc = DosLoadModule(fail, sizeof fail, dllname, &dlls->handle);
+	    if (rc)
+		Perl_warn_nocontext("Can't load DLL `%s', possible problematic module `%s'",
+				    dllname, fail);
+	    dlls++;
+	}
+    }
+    
+    {					/* Support message queue etc. */
+	os2_mytype = my_type();
+	/* Apparently, subprocesses (in particular, fork()) do not
+	   inherit the morphed state, so os2_mytype is the same as
+	   os2_mytype_ini. */
+
+	if (Perl_os2_initial_mode != -1
+	    && Perl_os2_initial_mode != os2_mytype) {
+					/* XXXX ??? */
+	}
+    }
+    if (Perl_HAB_set)
+	(void)_obtain_Perl_HAB;
+    if (Perl_hmq_refcnt) {
+	if (my_type() != 3)
+	    my_type_set(3);
+	Create_HMQ(Perl_hmq_servers != 0,
+		   "Cannot create a message queue on fork");
+    }
+
+    /* We may have loaded some modules */
+    _control87(fpflag, MCW_EM); /* Some modules reset FP flags on (un)load */
+  }
   return rc;
 }
+
--- ./os2/os2ish.h-as-sent	Mon May 26 14:13:34 2003
+++ ./os2/os2ish.h	Wed Jun 11 01:41:00 2003
@@ -313,6 +313,28 @@ void my_setpwent (void);
 void my_endpwent (void);
 char *gcvt_os2(double value, int digits, char *buffer);
 
+#define MAX_SLEEP	(((1<30) / (1000/4))-1)	/* 1<32 msec */
+
+static __inline__ unsigned
+my_sleep(unsigned sec)
+{
+  int remain;
+  while (sec > MAX_SLEEP) {
+    sec -= MAX_SLEEP;
+    remain = sleep(MAX_SLEEP);
+    if (remain)
+      return remain + sec;
+  }
+  return sleep(sec);
+}
+
+#define sleep		my_sleep
+
+#ifndef INCL_DOS
+unsigned long DosSleep(unsigned long);
+unsigned long DosAllocThreadLocalMemory (unsigned long cb, unsigned long **p);
+#endif
+
 struct group *getgrent (void);
 void setgrent (void);
 void endgrent (void);
@@ -331,6 +353,9 @@ struct passwd *my_getpwnam (__const__ ch
 #define strtoll	_strtoll
 #define strtoull	_strtoull
 
+#define usleep(usec)	((void)_sleep2(((usec)+500)/1000))
+
+
 /*
  * fwrite1() should be a routine with the same calling sequence as fwrite(),
  * but which outputs all of the bytes requested as a single stream (unlike
@@ -441,6 +466,7 @@ typedef struct OS2_Perl_data {
   unsigned long	phmq_refcnt;
   unsigned long	phmq_servers;
   unsigned long	initial_mode;		/* VIO etc. mode we were started in */
+  unsigned long	morph_refcnt;
 } OS2_Perl_data_t;
 
 extern OS2_Perl_data_t OS2_Perl_data;
@@ -464,6 +490,7 @@ extern OS2_Perl_data_t OS2_Perl_data;
 #define Perl_hmq_refcnt	(OS2_Perl_data.phmq_refcnt)
 #define Perl_hmq_servers	(OS2_Perl_data.phmq_servers)
 #define Perl_os2_initial_mode	(OS2_Perl_data.initial_mode)
+#define Perl_morph_refcnt	(OS2_Perl_data.morph_refcnt)
 
 unsigned long Perl_hab_GET();
 unsigned long Perl_Register_MQ(int serve);
@@ -616,6 +643,30 @@ enum entries_ordinals {
     ORD_WinQueryDesktopWindow,
     ORD_WinSetActiveWindow,
     ORD_DosQueryModFromEIP,
+    ORD_Dos32QueryHeaderInfo,
+    ORD_WinQueryActiveDesktopPathname,
+    ORD_WinInvalidateRect,
+    ORD_WinCreateFrameControls,
+    ORD_WinQueryClipbrdFmtInfo,
+    ORD_WinQueryClipbrdOwner,
+    ORD_WinQueryClipbrdViewer,
+    ORD_WinQueryClipbrdData,
+    ORD_WinOpenClipbrd,
+    ORD_WinCloseClipbrd,
+    ORD_WinSetClipbrdData,
+    ORD_WinSetClipbrdOwner,
+    ORD_WinSetClipbrdViewer,
+    ORD_WinEnumClipbrdFmts, 
+    ORD_WinEmptyClipbrd,
+    ORD_WinAddAtom,
+    ORD_WinFindAtom,
+    ORD_WinDeleteAtom,
+    ORD_WinQueryAtomUsage,
+    ORD_WinQueryAtomName,
+    ORD_WinQueryAtomLength,
+    ORD_WinQuerySystemAtomTable,
+    ORD_WinCreateAtomTable,
+    ORD_WinDestroyAtomTable,
     ORD_NENTRIES
 };
 
@@ -677,6 +728,21 @@ char *perllib_mangle(char *, unsigned in
 
 #define fork	fork_with_resources
 
+static __inline__ int
+my_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
+{
+  if (nfds == 0 && timeout && (_emx_env & 0x200)) {
+    if (DosSleep(1000 * timeout->tv_sec	+ (timeout->tv_usec + 500)/1000) == 0)
+      return 0;
+    errno = EINTR;
+    return -1;
+  }
+  return select(nfds, readfds, writefds, exceptfds, timeout);
+}
+
+#define select		my_select
+
+
 typedef int (*Perl_PFN)();
 Perl_PFN loadByOrdinal(enum entries_ordinals ord, int fail);
 extern const Perl_PFN * const pExtFCN;
@@ -688,7 +754,7 @@ int getpriority(int which /* ignored */,
 
 #ifdef PERL_CORE
 int os2_do_spawn(pTHX_ char *cmd);
-int os2_do_aspawn(pTHX_ SV *really, void **vmark, void **vsp);
+int os2_do_aspawn(pTHX_ SV *really, SV **vmark, SV **vsp);
 #endif
 
 #ifndef LOG_DAEMON
