Index: /trunk/src/kash/shfile.c
===================================================================
--- /trunk/src/kash/shfile.c	(revision 2295)
+++ /trunk/src/kash/shfile.c	(revision 2296)
@@ -43,5 +43,5 @@
 #endif
 
-#ifdef DEBUG
+#if defined(DEBUG) && defined(TRACE_VIA_STDIO)
 extern FILE *tracefile;
 #endif
@@ -150,10 +150,7 @@
         while (new_size < fdMin)
             new_size += SHFILE_GROW;
-        new_tab = sh_realloc(NULL, pfdtab->tab, new_size * sizeof(shfile));
+        new_tab = sh_realloc(shthread_get_shell(), pfdtab->tab, new_size * sizeof(shfile));
         if (new_tab)
         {
-            fd = i = pfdtab->size;
-            if (fd < fdMin)
-                fd = fdMin;
             for (i = pfdtab->size; i < new_size; i++)
             {
@@ -162,4 +159,8 @@
                 new_tab[i].native = -1;
             }
+
+            fd = pfdtab->size;
+            if (fd < fdMin)
+                fd = fdMin;
 
             pfdtab->tab = new_tab;
@@ -610,8 +611,8 @@
 #endif
 
-#ifdef DEBUG
+#if defined(DEBUG) && defined(TRACE_VIA_STDIO)
     if (tracefile)
+#endif
         TRACE2((NULL, "shfile_open(%p:{%s}, %#x, 0%o) -> %d [%d]\n", name, name, flags, mode, fd, errno));
-#endif
     return fd;
 }
@@ -999,5 +1000,7 @@
 
 #ifdef DEBUG
+# ifdef TRACE_VIA_STDIO
     if (tracefile)
+# endif
         switch (cmd)
         {
Index: /trunk/src/kash/shforkA-win.asm
===================================================================
--- /trunk/src/kash/shforkA-win.asm	(revision 2295)
+++ /trunk/src/kash/shforkA-win.asm	(revision 2296)
@@ -107,5 +107,4 @@
         mov     [rax - 10h], r10
         mov     [rax - 18h], r11
-int3
         cmp     rax, r10
         jb      .below
Index: /trunk/src/kash/shinstance.c
===================================================================
--- /trunk/src/kash/shinstance.c	(revision 2295)
+++ /trunk/src/kash/shinstance.c	(revision 2296)
@@ -302,4 +302,7 @@
 #endif
             psh->ttyfd = -1;
+
+            /* show.c */
+            psh->tracefd = -1;
 
             /* link it. */
Index: /trunk/src/kash/shinstance.h
===================================================================
--- /trunk/src/kash/shinstance.h	(revision 2295)
+++ /trunk/src/kash/shinstance.h	(revision 2296)
@@ -297,4 +297,9 @@
     struct redirtab    *redirlist;
     int                 fd0_redirected/* = 0*/;
+
+    /* show.c */
+    char                tracebuf[1024];
+    size_t              tracepos;
+    int                 tracefd;
 
     /* trap.h */
Index: /trunk/src/kash/show.c
===================================================================
--- /trunk/src/kash/show.c	(revision 2295)
+++ /trunk/src/kash/show.c	(revision 2296)
@@ -44,4 +44,5 @@
 #include <stdarg.h>
 #include <stdlib.h>
+#include <assert.h>
 
 #include "shell.h"
@@ -266,15 +267,138 @@
  */
 
-
+#ifdef DEBUG
+#ifdef TRACE_VIA_STDIO
 FILE *tracefile;
-
-
-#ifdef DEBUG
+#endif
+
+/** @def TRY_GET_PSH_OR_RETURN
+ * Make sure @a psh is valid, trying to fetch it from TLS
+ * if it's NULL and returning (void) if that fails. */
+# define TRY_GET_PSH_OR_RETURN(psh)  \
+	if (!(psh)) { \
+		psh = shthread_get_shell(); \
+		if (!psh) \
+			return; \
+	} else do { } while (0)
+
+/** @def RETURN_IF_NOT_TRACING
+ * Return if we're not tracing. */
+# ifdef TRACE_VIA_STDIO
+#  define RETURN_IF_NOT_TRACING(psh) \
+	if (debug(psh) != 1 || !tracefile)
+		return; \
+	else do	{} while (0)
+# else
+#  define RETURN_IF_NOT_TRACING(psh) \
+	if (debug(psh) != 1 || psh->tracefd == -1) \
+		return; \
+	else do	{} while (0)
+# endif
+
+/** @def TRACE_PUTC
+ * putc/trace_char wrapper. The @a psh / @a tracefile
+ * is taken from the context and not as a paramenter. */
+# ifdef TRACE_VIA_STDIO
+#  define TRACE_PUTC(c) 	fputc(c, tracefile)
+# else
+#  define TRACE_PUTC(c) 	trace_char(psh, c)
+# endif
+
+
+# ifndef TRACE_VIA_STDIO
+/* Flushes the tracebuf. */
+static void
+trace_flush(shinstance *psh)
+{
+	size_t pos = psh->tracepos;
+
+	if (pos > sizeof(psh->tracebuf)) {
+		char *end;
+		assert(0);
+		end = memchr(psh->tracebuf, '\0', sizeof(psh->tracebuf));
+		pos = end ? end - &psh->tracebuf[0] : 0;
+	}
+
+	if (pos) {
+		char 	prefix[40];
+		size_t 	len;
+
+		len = sprintf(prefix, "[%d] ", sh_getpid(psh));
+		shfile_write(&psh->fdtab, psh->tracefd, prefix, len);
+		shfile_write(&psh->fdtab, psh->tracefd, psh->tracebuf, pos);
+
+		psh->tracepos = 0;
+		psh->tracebuf[0] = '\0';
+	}
+}
+
+/* Adds a char to the trace buffer. */
+static void
+trace_char(shinstance *psh, int c)
+{
+	size_t pos = psh->tracepos;
+	if (pos >= sizeof(psh->tracebuf) - 1) {
+		trace_flush(psh);
+		pos = psh->tracepos;
+	}
+	psh->tracebuf[pos] = c;
+	psh->tracepos = pos + 1;
+	if (c == '\n')
+		trace_flush(psh);
+	else
+		psh->tracebuf[pos + 1] = '\0';
+}
+
+/* Add a string to the trace buffer. */
+static void
+trace_string(shinstance *psh, const char *str)
+{
+	/* push it out line by line. */
+	while (*str) {
+		/* find line/string length. */
+		size_t		pos;
+		size_t 		len;
+		const char *end = str;
+		int 		flush_it = 0;
+		while (*end) {
+			if (*end++ == '\n') {
+				flush_it = 1;
+				break;
+			}
+		}
+		len = end - str;
+
+		/* copy to the buffer */
+		pos = psh->tracepos;
+		if (pos + len <= sizeof(psh->tracebuf)) {
+			memcpy(&psh->tracebuf[pos], str, len);
+			psh->tracepos = pos + len;
+			if (flush_it)
+				trace_flush(psh);
+		} else {
+			/* it's too big for some reason... */
+			trace_flush(psh);
+			shfile_write(&psh->fdtab, psh->tracefd, str, len);
+			if (!flush_it)
+				shfile_write(&psh->fdtab, psh->tracefd, "[too long]\n", sizeof( "[too long]\n") - 1);
+		}
+
+		/* advance */
+		str = end;
+	}
+}
+# endif
+
 void
 trputc(shinstance *psh, int c)
 {
-	if (psh && debug(psh) != 1)
-		return;
-	putc(c, tracefile);
+	TRY_GET_PSH_OR_RETURN(psh);
+	RETURN_IF_NOT_TRACING(psh);
+
+# ifdef TRACE_VIA_STDIO
+    putc(c, tracefile);
+# else
+	trace_char(psh, c);
+# endif
 }
 #endif
@@ -286,11 +410,26 @@
 	int savederrno = errno;
 	va_list va;
-
-	if (!tracefile || (psh && debug(psh) != 1))
-		return;
+# ifndef TRACE_VIA_STDIO
+	char buf[2048];
+# endif
+
+	TRY_GET_PSH_OR_RETURN(psh);
+	RETURN_IF_NOT_TRACING(psh);
+
+# ifdef TRACE_VIA_STDIO
 	fprintf(tracefile, "[%d] ", sh_getpid(psh));
 	va_start(va, fmt);
 	(void) vfprintf(tracefile, fmt, va);
 	va_end(va);
+# else
+	va_start(va, fmt);
+#  ifdef _MSC_VER
+	_vsnprintf(buf, sizeof(buf), fmt, va);
+#  else
+	vsnprintf(buf, sizeof(buf), fmt, va);
+#  endif
+	va_end(va);
+	trace_string(psh, buf);
+# endif
 
 	errno = savederrno;
@@ -303,9 +442,22 @@
 #ifdef DEBUG
 	int savederrno = errno;
-
-	if (!tracefile || (psh && debug(psh) != 1))
-		return;
+# ifndef TRACE_VIA_STDIO
+	char buf[2048];
+# endif
+
+	TRY_GET_PSH_OR_RETURN(psh);
+	RETURN_IF_NOT_TRACING(psh);
+
+# ifdef TRACE_VIA_STDIO
 	fprintf(tracefile, "[%d] ", sh_getpid(psh));
 	(void) vfprintf(tracefile, fmt, va);
+# else
+#  ifdef _MSC_VER
+	_vsnprintf(buf, sizeof(buf), fmt, va);
+#  else
+	vsnprintf(buf, sizeof(buf), fmt, va);
+#  endif
+	trace_string(psh, buf);
+# endif
 
 	errno = savederrno;
@@ -320,7 +472,12 @@
 	int savederrno = errno;
 
-	if (!tracefile || (psh && debug(psh) != 1))
-		return;
+	TRY_GET_PSH_OR_RETURN(psh);
+	RETURN_IF_NOT_TRACING(psh);
+
+# ifdef TRACE_VIA_STDIO
 	fputs(s, tracefile);
+# else
+	trace_string(psh, s);
+# endif
 
 	errno = savederrno;
@@ -335,7 +492,8 @@
 	char c;
 
-	if (!tracefile || (psh && debug(psh) != 1))
-		return;
-	putc('"', tracefile);
+	TRY_GET_PSH_OR_RETURN(psh);
+	RETURN_IF_NOT_TRACING(psh);
+
+	TRACE_PUTC('"');
 	for (p = s ; *p ; p++) {
 		switch (*p) {
@@ -350,20 +508,20 @@
 		case CTLBACKQ:  c = 'q';  goto backslash;
 		case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
-backslash:	  putc('\\', tracefile);
-			putc(c, tracefile);
+backslash:	  TRACE_PUTC('\\');
+			TRACE_PUTC(c);
 			break;
 		default:
 			if (*p >= ' ' && *p <= '~')
-				putc(*p, tracefile);
+				TRACE_PUTC(*p);
 			else {
-				putc('\\', tracefile);
-				putc(*p >> 6 & 03, tracefile);
-				putc(*p >> 3 & 07, tracefile);
-				putc(*p & 07, tracefile);
+				TRACE_PUTC('\\');
+				TRACE_PUTC(*p >> 6 & 03);
+				TRACE_PUTC(*p >> 3 & 07);
+				TRACE_PUTC(*p & 07);
 			}
 			break;
 		}
 	}
-	putc('"', tracefile);
+	TRACE_PUTC('"');
 
 	errno = savederrno;
@@ -378,12 +536,13 @@
 	int savederrno = errno;
 
-	if (!tracefile || (psh && debug(psh) != 1))
-		return;
+	TRY_GET_PSH_OR_RETURN(psh);
+	RETURN_IF_NOT_TRACING(psh);
+
 	while (*ap) {
 		trstring(psh, *ap++);
 		if (*ap)
-			putc(' ', tracefile);
+			TRACE_PUTC(' ');
 		else
-			putc('\n', tracefile);
+			TRACE_PUTC('\n');
 	}
 
@@ -398,13 +557,25 @@
 {
     static const char s[] = "./trace";
+# ifdef TRACE_VIA_STDIO
 	int fd;
-
-	if (psh && debug(psh) != 1) {
+# endif
+
+	TRY_GET_PSH_OR_RETURN(psh);
+	if (debug(psh) != 1) {
+# ifdef TRACE_VIA_STDIO
 		if (tracefile)
 			fflush(tracefile);
 		/* leave open because libedit might be using it */
+# else
+		if (psh->tracefd != -1) {
+			trace_flush(psh);
+			shfile_close(&psh->fdtab, psh->tracefd);
+			psh->tracefd = -1;
+		}
+# endif
 		return;
 	}
 
+# ifdef TRACE_VIA_STDIO
 	if (tracefile) {
 		if (!freopen(s, "a", tracefile)) {
@@ -416,5 +587,5 @@
 		fd = open(s, O_APPEND | O_RDWR | O_CREAT, 0600);
 		if (fd != -1) {
-# if K_OS == K_OS_WINDOWS
+#  if K_OS == K_OS_WINDOWS
             int fds[50];
             int i = 0;
@@ -431,18 +602,17 @@
             while (i-- > 0)
                 close(fds[i]);
-# else
+#  else
             int fdTarget = 199;
             while (fdTarget > 10)
             {
                 int fd2 = shfile_fcntl(&psh->fdtab, fd, F_DUPFD, fdTarget);
-                if (fd2 != -1)
-                    break;
+				if (fd2 != -1) {
+					close(fd);
+					fd = fd2;
+					break;
+				}
                 fdTarget = (fdTarget + 1 / 2) - 1;
             }
-			if (fd2 != -1) {
-				close(fd);
-				fd = fd2;
-			}
-# endif
+#  endif
 		}
 		if (fd == -1 || (tracefile = fdopen(fd, "a")) == NULL) {
@@ -454,4 +624,32 @@
 	setvbuf(tracefile, (char *)NULL, _IOLBF, 1024);
 	fputs("\nTracing started.\n", tracefile);
+
+# else  /* !TRACE_VIA_STDIO */
+	if (psh->tracefd != -1) {
+		return;
+	}
+	psh->tracefd = shfile_open(&psh->fdtab, s, O_APPEND | O_RDWR | O_CREAT, 0600);
+	if (psh->tracefd != -1) {
+		/* relocate it */
+		int fdTarget = 199;
+		while (fdTarget > 10)
+		{
+			int fd2 = shfile_fcntl(&psh->fdtab, psh->tracefd, F_DUPFD, fdTarget);
+			if (fd2 != -1) {
+				shfile_close(&psh->fdtab, psh->tracefd);
+				psh->tracefd = fd2;
+				break;
+			}
+			fdTarget = (fdTarget + 1 / 2) - 1;
+		}
+	}
+	if (psh->tracefd == -1) {
+		fprintf(stderr, "Can't open %s\n", s);
+		debug(psh) = 0;
+		return;
+	}
+	trace_string(psh, "Tracing started.\n");
+
+# endif /* !TRACE_VIA_STDIO */
 }
 #endif /* DEBUG */
Index: /trunk/src/kash/shthread.c
===================================================================
--- /trunk/src/kash/shthread.c	(revision 2295)
+++ /trunk/src/kash/shthread.c	(revision 2296)
@@ -27,7 +27,11 @@
 #include "shthread.h"
 #include "shinstance.h"
+#include <assert.h>
 
-#if defined(_MSC_VER) || defined(__EMX__)
-# include <process.h>
+#if K_OS == K_OS_WINDOWS
+# include <Windows.h>
+#elif K_OS == K_OS_OS2
+# include <InnoTekLIBC/FastInfoBlocks.h>
+# include <InnoTekLIBC/thread.h>
 #else
 # include <pthread.h>
@@ -35,14 +39,72 @@
 
 
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+#if K_OS == K_OS_WINDOWS
+static DWORD sh_tls = TLS_OUT_OF_INDEXES;
+#elif K_OS == K_OS_OS2
+static int sh_tls = -1;
+#else
+static int sh_tls_inited = 0;
+static int sh_tls;
+#endif
+
+
+/**
+ * Stores the shell instance pointer in a TLS entry.
+ *
+ * This will allocate the TLS entry on the first call. We assume
+ * there will no be races at that time.
+ *
+ * @param   psh     The shell instance.
+ */
 void shthread_set_shell(struct shinstance *psh)
 {
+#if K_OS == K_OS_WINDOWS
+    if (sh_tls == TLS_OUT_OF_INDEXES)
+    {
+        sh_tls = TlsAlloc();
+        assert(sh_tls != TLS_OUT_OF_INDEXES);
+    }
+    if (!TlsSetValue(sh_tls, psh))
+        assert(0);
 
+#elif K_OS == K_OS_OS2
+    if (sh_tls == -1)
+    {
+        sh_tls = __libc_TLSAlloc();
+        assert(sh_tls != -1);
+    }
+    if (__libc_TLSSet(sh_tls, psh) == -1)
+        assert(0);
+#else
+    if (!sh_tls_inited)
+    {
+        if (pthread_key_create(&sh_tls, NULL) != 0)
+            assert(0);
+        sh_tls_inited = 1;
+    }
+    if (pthread_setspecific(sh_tls, psh) != 0)
+        assert(0);
+#endif
 }
 
+/**
+ * Get the shell instance pointer from TLS.
+ *
+ * @returns The shell instance.
+ */
 struct shinstance *shthread_get_shell(void)
 {
-    shinstance *psh = NULL;
+    shinstance *psh;
+#if K_OS == K_OS_WINDOWS
+    psh = (shinstance *)TlsGetValue(sh_tls);
+#elif K_OS == K_OS_OS2
+    psh = (shinstance *)__libc_TLSGet(iTls)
+#else
+    psh = (shinstance *)pthread_getspecific(sh_tls);
+#endif
     return psh;
 }
 
-
