From 0c57f42f9e1bd459a95596b4d70e06f9a7b31148 Mon Sep 17 00:00:00 2001
From: rpj <rpj>
Date: Fri, 24 Jul 1998 03:58:18 +0000
Subject: 	* sync.c (pthread_join): Save valueptr arg in joinvalueptr for
 	pthread_exit() to use.

	* private.c (_pthread_new_thread_entry): Initialise joinvalueptr to
	NULL.

	* create.c (_pthread_start_call): Rewrite to facilitate joins.
	pthread_exit() will do a longjmp() back to here. Does appropriate
	cleanup and exit/return from the thread.
	(pthread_create): _beginthreadex() now passes a pointer to our
	thread table entry instead of just the call member of that entry.

	* implement.h (_pthread_threads_thread): New member
	void ** joinvalueptr.
	(_pthread_call_t): New member jmpbuf env.

	* exit.c (pthread_exit): Major rewrite to handle joins and handing
	value pointer to joining thread. Uses longjmp() back to
	_pthread_start_call().
---
 ChangeLog   | 20 ++++++++++++++++++++
 create.c    | 34 +++++++++++++++++++++++-----------
 exit.c      | 15 +++++++++++++--
 implement.h |  2 ++
 private.c   |  1 +
 sync.c      |  2 ++
 6 files changed, 61 insertions(+), 13 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 102ef6f..29b2289 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,25 @@
 Fri Jul 24 03:00:25 1998  Ross Johnson  <rpj@ixobrychus.canberra.edu.au>
 
+	* sync.c (pthread_join): Save valueptr arg in joinvalueptr for
+	pthread_exit() to use.
+
+	* private.c (_pthread_new_thread_entry): Initialise joinvalueptr to
+	NULL.
+
+	* create.c (_pthread_start_call): Rewrite to facilitate joins.
+	pthread_exit() will do a longjmp() back to here. Does appropriate
+	cleanup and exit/return from the thread.
+	(pthread_create): _beginthreadex() now passes a pointer to our
+	thread table entry instead of just the call member of that entry.
+
+	* implement.h (_pthread_threads_thread): New member 
+	void ** joinvalueptr.
+	(_pthread_call_t): New member jmpbuf env.
+
+	* exit.c (pthread_exit): Major rewrite to handle joins and handing
+	value pointer to joining thread. Uses longjmp() back to 
+	_pthread_start_call().
+
 	* create.c (pthread_create): Ensure values of new attribute members
 	are copied to the thread attribute object.
 
diff --git a/create.c b/create.c
index 498f649..e15a98f 100644
--- a/create.c
+++ b/create.c
@@ -12,26 +12,38 @@
 #include "implement.h"
 
 unsigned
-_pthread_start_call(void * call)
+_pthread_start_call(void * thisarg)
 {
   /* We're now in a running thread. Any local variables here are on
      this threads private stack so we're safe to leave data in them
      until we leave. */
-  _pthread_call_t * this;
+  _pthread_threads_thread__t * this = thisarg;
+  _pthread_call_t * call;
   unsigned (*func)(void *);
   void * arg;
   unsigned ret;
+  int from;
 
-  this = (_pthread_call_t *) call;
-  func = call->routine;
-  arg = call->arg;
+  func = this->call.routine;
+  arg = this->call.arg;
 
-  ret = (*func)(arg);
+  /* FIXME: Should we be using sigsetjmp() here instead. */
+  from = setjmp(this->call.env);
 
-  /* If we get to here then we're returning naturally and haven't
-     been cancelled. We need to cleanup and remove the thread
-     from the threads table. */
-  _pthread_vacuum();
+  if (from == 0)
+    {
+      ret = (*func)(arg);
+
+      _pthread_vacuum();
+    }
+  else
+    {
+      /* func() called pthread_exit() which called longjmp(). */
+      _pthread_vacuum();
+
+      /* Never returns. */
+      _endthreadex(0);
+    }
 
   return ret;
 }
@@ -75,7 +87,7 @@ pthread_create(pthread_t *thread,
       handle = (HANDLE) _beginthreadex(security,
 				       attr_copy->stacksize,
 				       _pthread_start_call,
-				       (void *) &(this->call),
+				       (void *) this,
 				       flags,
 				       &threadID);
 
diff --git a/exit.c b/exit.c
index a9c352c..1e07ccd 100644
--- a/exit.c
+++ b/exit.c
@@ -36,6 +36,17 @@ _pthread_vacuum(void)
 void
 pthread_exit(void * value)
 {
-  _pthread_vacuum();
-  _endthreadex((DWORD) value);
+  _pthread_threads_thread_t * this;
+
+  this = _PTHREAD_THIS;
+
+  if (this->joinvalueptr != NULL)
+    {
+      *(this->joinvalueptr) = value;
+    }
+
+  /* FIXME: More to do here. IE, if pthread_detach() was called
+     and value != NULL, do we free(value)? */
+
+  longjmp(this->call.env, 1);
 }
diff --git a/implement.h b/implement.h
index 14fbdbb..b72e273 100644
--- a/implement.h
+++ b/implement.h
@@ -37,6 +37,7 @@ struct _pthread_handler_node {
 typedef struct {
   unsigned (*routine)(void *);
   void * arg;
+  jmpbuf env;
 } _pthread_call_t;
 
 #define _PTHREAD_THIS (_pthread_find_thread_entry(pthread_this()))
@@ -51,6 +52,7 @@ struct _pthread_threads_thread {
   pthread_t                   thread;
   pthread_attr_t              attr;
   _pthread_call_t             call;
+  void **                     joinvalueptr;
   _pthread_handler_node_t *   cleanupstack;
   _pthread_handler_node_t *   destructorstack;
   _pthread_handler_node_t *   forkpreparestack;
diff --git a/private.c b/private.c
index e65e95e..dc7e111 100644
--- a/private.c
+++ b/private.c
@@ -59,6 +59,7 @@ _pthread_new_thread_entry(pthread_t thread, _pthread_threads_thread_t * entry)
     {
       this->thread = thread;
       pthread_attr_init(&(this->attr));
+      this->joinvalueptr = NULL;
       this->cleanupstack = NULL;
       this->destructorstack = NULL;
       this->forkpreparestack = NULL;
diff --git a/sync.c b/sync.c
index c3bd438..e8262a6 100644
--- a/sync.c
+++ b/sync.c
@@ -37,6 +37,8 @@ pthread_join(pthread_t thread, void ** valueptr)
       return EINVAL;
     }
 
+  this->joinvalueptr = valueptr;
+
   /* Wait on the kernel thread object. */
   switch (WaitForSingleObject(thread, INFINITE))
     {
-- 
cgit v1.2.3