diff --git a/TODO b/TODO
deleted file mode 100644
index 431153197594d50690812811561a9cc08be857ac..0000000000000000000000000000000000000000
--- a/TODO
+++ /dev/null
@@ -1,5 +0,0 @@
-1. Clean up compiler #defines
-8. Check NP routines.
-9. Check for printfs
-10. Remove  -Werror from Makefiles
-
diff --git a/doc/pte_dspbios.html b/doc/pte_dspbios.html
new file mode 100644
index 0000000000000000000000000000000000000000..488b963bc5196f0f65c74e8327a26e1e2a2de9eb
--- /dev/null
+++ b/doc/pte_dspbios.html
@@ -0,0 +1,108 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html><head><meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"><title>PTE on DSP/BIOS</title></head><body><br><big><big><big><span style="font-weight: bold;">PTE on DSP/BIOS</span></big></big></big><meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8"><title></title><meta name="GENERATOR" content="OpenOffice.org 2.3  (Linux)">
+	
+	
+	<style type="text/css">
+	<!--
+		@page { size: 8.5in 11in; margin: 0.79in }
+		P { margin-bottom: 0.08in }
+		H1 { margin-bottom: 0.08in }
+		H1.western { font-family: "Helvetica"; font-size: 16pt }
+		H1.cjk { font-family: "AR PL ShanHeiSun Uni"; font-size: 16pt }
+		H1.ctl { font-family: "Tahoma"; font-size: 16pt }
+		H2 { margin-bottom: 0.08in }
+		H2.western { font-family: "Helvetica"; font-size: 14pt; font-style: italic }
+		H2.cjk { font-family: "AR PL ShanHeiSun Uni"; font-size: 14pt; font-style: italic }
+		H2.ctl { font-size: 14pt; font-style: italic }
+	-->
+	</style>
+
+<p style="margin-bottom: 0in;"><br>
+</p>
+<p style="margin-bottom: 0in;">The DSP/BIOS OSAL is relatively
+straightforward and maps relatively cleanly to the DSP/BIOS API.  For
+instance, most mutex and semaphore operations are supported directly
+using the LCK and SEM API's.  Specific details and exceptions are
+described below.</p>
+<h1 class="western">Threads</h1>
+<h2 class="western">Thread creation</h2>
+<p>OsThreadCreate allocates a dspbiosThreadData structure that
+contains semaphores used for joining to a thread, cancelling a thread
+and the initial priority requested by the user.  A pointer to this
+structure is stored as a TLS value.  
+</p>
+<p>OsThreadCreate must create threads in a suspended state.  In
+DSP/BIOS this is done by setting the initial priority to zero.  The
+initial priority is stored in the per thread control data.  When
+OsThreadStart is called, it retrieves the initial priority from the
+control data attached to the thread and then sets the priority of the
+thread, which starts execution.</p>
+<h2 class="western">Thread termination</h2>
+<p>In order for pthread_join to wait for a thread, OsThreadWaitForEnd
+is called.   Since DSP/BIOS doesn't have a explicit system call for
+this, we emulate it using a semaphore that is posted to when the
+thread exits.  This semaphore is saved in the per thread control
+structure.</p>
+<h2 class="western">Thread cleanup</h2>
+<p style="margin-bottom: 0in;"><br>
+</p>
+<p style="margin-bottom: 0in;">The PTE library calls <font face="Courier New, monospace">OsThreadDelete</font>
+to signal to the OSAL that the resources for a task can be freed. 
+For DSP/BIOS, this means a call to TSK_delete (task resources are <i>not</i><span style="font-style: normal;">
+automatically freed by DSP/BIOS when the thread exits).</span></p>
+<p style="margin-bottom: 0in; font-style: normal;"><br>
+</p>
+<p style="margin-bottom: 0in;"><font face="Courier New, monospace"><span style="font-style: normal;">OsThreadDelete</span></font><span style="font-style: normal;">
+will be called at a number of points.  For attached threads, it will
+be called when </span><font face="Courier New, monospace"><span style="font-style: normal;">pthread_join</span></font><span style="font-style: normal;">
+is called and returns or when </span><font face="Courier New, monospace"><span style="font-style: normal;">pthread_detach</span></font><span style="font-style: normal;">
+is called for a terminated thread.  For detached threads
+</span><font face="Courier New, monospace"><span style="font-style: normal;">OsThreadDelete</span></font><span style="font-style: normal;">
+will be called when the thread exits.</span></p>
+<p style="margin-bottom: 0in; font-style: normal;"><br>
+</p>
+<p style="margin-bottom: 0in;"><span style="font-style: normal;">The
+problem is that </span><font face="Courier New, monospace"><span style="font-style: normal;">TSK_delete</span></font><span style="font-style: normal;">
+naturally can not be called from the same context as the thread that
+we're trying to free.  For the first two cases (</span><font face="Courier New, monospace"><span style="font-style: normal;">pthread_join</span></font><span style="font-style: normal;">
+and </span><font face="Courier New, monospace"><span style="font-style: normal;">pthread_detach</span></font><span style="font-style: normal;">)
+this is not a problem as these will always be called from another
+thread.  However, for detached threads </span><font face="Courier New, monospace"><span style="font-style: normal;">OsThreadDelete</span></font><span style="font-style: normal;">
+will be called from the same context.</span></p>
+<p style="margin-bottom: 0in; font-style: normal;"><br>
+</p>
+<p style="margin-bottom: 0in;"><span style="font-style: normal;">To
+work around it, the DSP/BIOS OSAL includes a low priority that will
+clean up detached threads.  If </span><font face="Courier New, monospace"><span style="font-style: normal;">OsThreadDelete</span></font><span style="font-style: normal;">
+detects that it is being called from the same context, it will post a
+message to a mailbox that the garbage collector thread is waiting on.
+ The garbage collector thread will then call </span><font face="Courier New, monospace"><span style="font-style: normal;">TSK_delete</span></font><span style="font-style: normal;">
+for that thread, as well as to clean up any resources that were
+allocated when the thread was created.</span></p>
+<p style="margin-bottom: 0in;"><br>
+</p>
+<h1 class="western">Thread Local Storage</h1>
+<p style="margin-bottom: 0in;"><br>
+</p>
+<p style="margin-bottom: 0in;">TLS is implemented using the
+&#8220;environment&#8221; of DSP/BIOS threads.  This allows a single value to
+be associated with a thread.  The TLS helper routines are used to
+provide full TLS functionality; these routines allocate a structure
+that holds multiple TLS keys and values.  The DSP/BIOS environment is
+used to hold a pointer to this structure.</p>
+<p style="margin-bottom: 0in;"><br>
+</p>
+<h1 class="western">Thread Cancellation</h1>
+<p style="margin-bottom: 0in;"><br>
+</p>
+<p style="margin-bottom: 0in;">Since DSP/BIOS does not natively
+provide a way to break out of blocked operations, this functionality
+is emulated using a cancellation semaphore that is stored in the per
+thread control data.  When the user requests that a thread be
+canceled (i.e. <font face="Courier New, monospace">OsThreadCancel</font>
+is called) this semaphore is posted to.  In
+<font face="Courier New, monospace">OsSemaphoreCancellablePend</font>,
+the cancellation semaphore as well as the user semaphore are polled
+(rather than blocking) and the routine returns if the cancellation
+semaphore is posted to.</p>
+</body></html>
\ No newline at end of file
diff --git a/doc/pte_main.html b/doc/pte_main.html
new file mode 100644
index 0000000000000000000000000000000000000000..8841bed84933240031bfd681708f8b18dc15a061
--- /dev/null
+++ b/doc/pte_main.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html><head>
+<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"><title>POSIX Threads for embedded systems (PTE)</title>
+
+</head><body>
+<font style="font-weight: bold;" size="+2"></font><br><big style="font-family: Helvetica,Arial,sans-serif; font-weight: bold;"><big><big>POSIX Threads for embedded systems (PTE)<br><br><span style="font-weight: bold;"><span style="font-weight: bold;"></span></span></big></big></big><big style="font-family: Helvetica,Arial,sans-serif;"><big><big><small><small>PTE is an open source implementation of the <a href="http://www.unix.org/version3/ieee_std.html">POSIX API</a>
+for multithreaded applications (pthreads). &nbsp;It is intended to be
+used to provide a pthreads API for&nbsp;embedded operating systems that
+do not natively provide a pthreads API. PTE is designed to be easily
+portable to such operating systems and only relies on basic primitives
+(e.g. semaphores) that are widely supported on most embedded operating
+systems.<br><br>Currently, PTE has been ported to Texas Instrument's DSP/BIOS and Sony's PSP OS.<br><br><a href="http://sourceforge.net/project/showfiles.php?group_id=213842">Download</a><br><a href="mailto:jschmidlapp@users.sourceforge.net">Contact</a><span style="font-weight: bold;"><br><br><big>Documentation</big><br></span><a href="pte_users_guide.html">User's Manual</a><span style="font-weight: bold;"><span style="font-weight: bold;"><span style="font-weight: bold;"><br></span></span></span><a href="pte_porting_guide.html">Porting Guide</a><br><a href="pte_dspbios.html">Notes on DSP/BIOS port</a><br><a href="pte_psp.html">Notes on PSP OS port</a><span style="font-weight: bold;"><span style="font-weight: bold;"><span style="font-weight: bold;"><br><br><br></span></span><br><br></span></small></small></big></big></big></body></html>
\ No newline at end of file
diff --git a/doc/pte_porting_guide.html b/doc/pte_porting_guide.html
new file mode 100644
index 0000000000000000000000000000000000000000..d9f22be65309435a185a98a1dcfff83c8e2bc293
--- /dev/null
+++ b/doc/pte_porting_guide.html
@@ -0,0 +1,267 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html><head><meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"><title>PTE Porting Guide</title></head><body>
+
+
+	<meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8"><title></title><meta name="GENERATOR" content="OpenOffice.org 2.3  (Linux)"><meta name="CHANGEDBY" content="Jason"><meta name="CHANGEDBY" content="Jason"><meta name="CHANGEDBY" content="Jason"><meta name="CHANGEDBY" content="Jason">
+	
+	
+	
+	
+	
+	
+	<style type="text/css">
+	<!--
+		@page { size: 8.5in 11in; margin: 0.79in }
+		P { margin-bottom: 0.08in }
+		H1 { margin-bottom: 0.08in }
+		H1.western { font-family: "Helvetica"; font-size: 16pt }
+		H1.cjk { font-family: "AR PL ShanHeiSun Uni"; font-size: 16pt }
+		H1.ctl { font-family: "Tahoma"; font-size: 16pt }
+		H2 { margin-bottom: 0.08in }
+		H3 { margin-bottom: 0.08in }
+		P.code-western { font-family: "Courier New", monospace }
+	-->
+	</style>
+
+<p style="margin-bottom: 0in;"><br>
+</p>
+<h1 class="western" align="center">Pthreads-Embedded (PTE) Porting
+Guide</h1>
+<p>The PTE library consists of both a platform independent component,
+which contains the bulk of the pthreads functionality, and a platform
+specific component which connects the platform independent component
+to the underlying OS. Naturally, the platform specific layer is the
+only layer that needs to be modified when porting PTE.</p>
+<p>The OS adaptation layer (OSAL) must provide the following
+functionality:</p>
+<ol><li><p>Threads</p>
+	</li><li><p>Semaphores</p>
+	</li><li><p>Mutexes</p>
+	</li><li><p>Atomic operations</p>
+	</li><li><p>Thread local storage</p>
+</li></ol>
+<p>The underlying OS does not necessarily have to provide all of this
+functionality &#8211; it is possible for the OSAL to emulate behavior.
+For instance, mutexes can be emulated using semaphores provided by
+the OS. The sections below present a high level of the required
+functionality as well as how it fits into a &#8220;typical&#8221; embedded
+OS. Specifics such as function parameters, etc are covered in the
+OSAL API reference.</p>
+<h2 align="center">Threads</h2>
+<h3>Thread Initialization</h3>
+<p class="code-western"><b>OsThreadCreate, OsThreadStart</b></p>
+<p>Thread initialization is separated into two steps: create and
+start. When <font face="Courier New, monospace">OSThreadCreate</font>
+is called, the OS should create a new thread, but it must be started
+in a suspended state. The thread should not start executing until
+<font face="Courier New, monospace">OSThreadStart</font> is called.
+This separation in functionality is due necessary to avoid race
+condFor instance, if the target OS supports TLS but only allows a
+single TLS value, this single value could contain a pointer to a
+structure that contains multiple TLS values.  The PTE distribution
+includes a helper file to implement this functionality
+(/platform/helper/tls-helper.c).  See the DSP/BIOS port for an
+example of using tls-helper.c.itions in the PTE library<span style="font-style: normal;">.</span></p>
+<p><span style="font-style: normal;">Since the actual prototype of an
+thread entry point varies between OS and thus will more than likely
+</span><i>not</i> <span style="font-style: normal;">match that used by
+</span><font face="Courier New, monospace"><span style="font-style: normal;">OsThreadCreate</span></font><span style="font-style: normal;">,
+it will usually be necessary to create a stub function that matches
+your OS's entry point prototype. This stub function simply calls the
+entry point specified by </span><font face="Courier New, monospace"><span style="font-style: normal;">OsThreadCreate</span></font>
+<span style="font-style: normal;">(see DSP/BIOS and PSP-OS ports).</span></p>
+<p>Typically, OsThreadCreate will also perform other initialization;
+for instance to initialize TLS structures, allocate other control
+resources. This of course varies depending on the target OS. 
+</p>
+<p>Some OS's require additional parameters to start a thread.  For
+instance, DSP/BIOS requires the priority in order to start the
+thread.  Rather than pass these parameters to both <font face="Courier New, monospace">OsThreadCreate</font>
+and <font face="Courier New, monospace">OsThreadStart</font>, the
+OSAL should store any necessary information as thread specific values
+during <font face="Courier New, monospace">OsThreadCreate</font> and
+then retrieve them as necessary in <font face="Courier New, monospace">OsThreadStart</font>.</p>
+<p><br><br>
+</p>
+<h3>Thread Destruction</h3>
+<p class="code-western"><b>OsThreadExit, OsThreadDelete,
+OsThreadExitAndDelete, OsThreadWaitForEnd</b></p>
+<p>Thread destruction is broken into three API calls to support the
+different use cases of the pthreads API.  <font face="Courier New, monospace">OsThreadExit</font>
+should cause the currently executing thread to stop execution;
+resources should not yet be freed.  This is called when a thread
+exits but the thread is not detached &#8211; resource deallocation must
+wait until the user calls <font face="Courier New, monospace">pthread_join</font>
+(or <font face="Courier New, monospace">pthread_detach</font>) at
+which point <font face="Courier New, monospace">OsThreadDelete</font>
+will be called.</p>
+<p>Alternatively, if a detached thread exits, thread resource
+deallocation and thread termination can occur simultaneously.  In
+this case, <font face="Courier New, monospace">OsThreadExitAndDelete</font>
+will be called.</p>
+<p><font face="Courier New, monospace">OsThreadWaitForEnd</font>
+should block until the specified thread exists. For OS's that do not
+directly support this functionality, a semaphore can be used to
+emulate this behavior (see DSP/BIOS port).  Note that this call
+should be cancellable &#8211; that is, it should return (even if the
+target thread has not exited) if <font face="Courier New, monospace">OsThreadCancel</font>
+is called.</p>
+<h3>Thread Priority</h3>
+<p class="code-western"><b>OsThreadSetPriority, OsThreadGetPriority,
+OsThreadGetMaxPriority, OsThreadGetMinPriority</b></p>
+<p>The OSAL provides the upper and lower bounds of it's priority
+range when <font face="Courier New, monospace">OsThreadGetMaxPriority</font>
+and <font face="Courier New, monospace">OsThreadGetMinPriority</font>
+are called.  The PTE library will ensure that all priorities passed
+to the OSAL (e.g. through <font face="Courier New, monospace">OsThreadCreate</font>)
+are within these bounds.</p>
+<h3>Thread Cancellation</h3>
+<p class="code-western"><b>OsThreadCancel, OsThreadCheckCancel</b></p>
+<p>Currently, the PTE library only supports deferred cancellation
+(see PTE notes). While the PTE library handles most of the
+complexities of cancellation, there are three hooks required from the
+OSAL. When <font face="Courier New, monospace">OsThreadCancel</font>
+is called, it must cause <font face="Courier New, monospace">OsSemaphorePendCancellable</font>
+and <font face="Courier New, monospace">OsThreadWaitForEnd </font>to
+return (this function is used by the PTE library to implement pthread
+cancellation points). Since most embedded OS's do not support this
+kind of functionality, it can be implemented using semaphores (see
+DSP/BIOS and PSP-OS ports). <font face="Courier New, monospace">OsThreadCheckCancel</font>
+simply returns whether <font face="Courier New, monospace">OsThreadCancel</font>
+has been called for this thread.</p>
+<h3>Miscellaneous Thread Functionality</h3>
+
+<p class="code-western"><b>OsThreadGetHandle, OsThreadSleep,
+OsThreadGetMaxPriority, OsThreadGetMinPriority,
+OsThreadGetDefaultPriority</b><br><br>
+</p>
+<h2 align="center"></h2>
+<h2 style="page-break-before: always;" align="center">Semaphores</h2>
+<p align="center"><br><br>
+</p>
+<p class="code-western"><b>OsSemaphoreCreate, OsSemaphoreDelete,
+OsSemaphorePend, OsSemaphorePort</b></p>
+<p>This basic semaphore functionality should map directly to almost
+all embedded OS's. 
+</p>
+<p class="code-western"><b>OsSemaphoreCancellablePend</b></p>
+<p>In order to implement deferred cancellation, a &#8220;cancellable&#8221;
+pend (<font face="Courier New, monospace">OsSemaphorePendCancellable</font>)
+must also be supported. As discussed above,
+<font face="Courier New, monospace">OsSemaphorePendCancellable</font>
+must return when <font face="Courier New, monospace">OsThreadCancel</font>
+has been called on the thread that is currently pending, regardless
+of whether the semaphore has been posted to or not. The way that this
+is implemented in other ports (e.g. DSP/BIOS and PSP-OS) is to use an
+additional semaphore, and then poll on both semaphores, as shown in
+the pseudo-code below:</p>
+
+<p><font face="Courier New, monospace">loop forever:</font></p>
+<p><font face="Courier New, monospace">poll main semaphore</font></p>
+<p><font face="Courier New, monospace">if semaphore was posted to,
+return OK</font></p>
+<p><font face="Courier New, monospace">else</font></p>
+<p><font face="Courier New, monospace">check timeout</font></p>
+<p><font face="Courier New, monospace">if timeout has expired, return
+'timed out'</font></p>
+<p><font face="Courier New, monospace">else</font></p>
+<p><font face="Courier New, monospace">poll cancellation semaphore </font>
+</p>
+<p><font face="Courier New, monospace">if cancellation semaphore has
+been posted to, return 'canceled'</font></p>
+<p><font face="Courier New, monospace">else</font></p>
+<p><font face="Courier New, monospace">sleep for small amount of time</font></p>
+<p>For instance, if the target OS supports TLS but only allows a
+single TLS value, this single value could contain a pointer to a
+structure that contains multiple TLS values.  The PTE distribution
+includes a helper file to implement this functionality
+(/platform/helper/tls-helper.c).  See the DSP/BIOS port for an
+example of using tls-helper.c.</p>
+<h2 align="center">Mutexes</h2>
+<p>Mutexes are only included as an optimization as some OS's mutex
+operation is much faster than semaphore operations. If the target OS
+does not support mutexes, they can easily be implemented using
+semaphores.</p>
+<p><br><br>
+</p>
+<h2 align="center">Atomic operations</h2>
+<p class="code-western"><b>OsAtomicExchange, OsAtomicCompareExchange,
+OsAtomicExchangeIncrement, OsAtomicDecrement, OsAtomicIncrement</b></p>
+<p align="left">The PTE library requires five atomic operations to be
+supplied by the OSAL.  Macros are used in case the target platform
+supports direct assembly instructions to perform some or all of these
+operations.  However, under most OS's these macros will simply refer
+to functions that disable interrupts and then perform the required
+operations.</p>
+<p><br><br>
+</p>
+<h2 align="center">Thread local storage</h2>
+<p class="code-western"><b>OsTlsInit, OsTlsAlloc, OsTlsFree,
+OsTlsSetValue, OsTlsGetValue</b></p>
+<p>The OSAL must be able to allocate and free TLS keys, and retrieve
+thread specific data.  If the target OS does not support this level
+of TLS functionality, but does have limited TLS support, it is
+possible to emulate the behavior required by the PTE library.</p>
+<p>For instance, if the target OS supports TLS but only allows a
+single TLS value, this single value could contain a pointer to a
+structure that contains multiple TLS values.  The PTE distribution
+includes a helper file to implement this functionality
+(/platform/helper/tls-helper.c).  See the DSP/BIOS port for an
+example of using tls-helper.c.</p>
+<p>If the OS contains no TLS support, it might still be possible to
+emulate TLS functionality.  See the PSP-OS port for an example of how
+this can be accomplished.  Be warned &#8211; it is not a pretty solution,
+but it works.</p>
+<p>It is important to note that TLS functionality is <i>required </i><span style="font-style: normal;">by
+the PTE library &#8211; it is used for more than just the pthread TLS
+functions, but is used extensively throughout the library.</span></p>
+<p style="font-style: normal;">One potentially tricky issue with TLS
+is how to handle the case of when pthread TLS functions are called
+from non-pthread threads (i.e. pure native threads that were not
+created through pthread_create).  Technically, according to the
+pthread spec, this should work.  However, it is problematic in that
+OsTlsInit would not have been called for that thread, since it is
+called in response to pthread_create().  Different ports handle this
+differently &#8211; see the notes for a particular ports.</p>
+<h2 align="center">Miscellaneous Functionality</h2>
+<p class="code-western"><b>ftime</b></p>
+<p>Since pthreads uses absolute time for timeouts, the PTE library
+requires the OS to supply the current time.  Note that this does not
+have to be the actual world time, but can be an internal timebase
+(for example, since the unit started up).   However, the time source
+should be the same one that the caller to pthread would use.</p>
+<h2 align="center">Types and Constants</h2>
+<p align="left">The OSAL layer must declare a number of types and
+constants.  
+</p>
+<p align="left">The following types must be defined to map to the
+appropriate OS constructs:</p>
+<p class="code-western">OsThreadHandle</p>
+<p class="code-western">OsSemaphoreHandle</p>
+
+<p class="code-western">OsMutexHandle<br><br><br>
+</p>
+<p>The following constants must be defined:</p>
+<p align="left"><font face="Courier New, monospace">OS_DEFAULT_PRIO</font>
+&#8211; default priority for a created thread.</p>
+<p align="left"><font face="Courier New, monospace">OS_MIN_PRIO</font>
+&#8211; minimum thread priority.</p>
+<p align="left"><font face="Courier New, monospace">OS_MAX_PRIO</font>
+&#8211; maximum thread priority.</p>
+<p align="left"><font face="Courier New, monospace">OS_MAX_SIMUL_THREADS</font>
+&#8211; maximum number of threads that may be active simultaneously.</p>
+<p align="left"><br><br>
+</p>
+<p align="left">Each port must also include a file, pte_types.h, that
+defines all of the following types.  This may be done by explicitly
+typedef'ing the structure (for OS's that do not natively support the
+type) or simply by including the appropriate header file:</p>
+<p align="left"><font face="Courier New, monospace">pid_t</font></p>
+<p align="left"><font face="Courier New, monospace">struct timespec</font></p>
+<p align="left"><font face="Courier New, monospace">mode_t</font></p>
+<p align="left"><font face="Courier New, monospace">struct timeb</font></p>
+<h2 align="center">File structure</h2>
+<p align="left">The OSAL layer must include a file named pte_osal.h. 
+This file must include pte_generic_osal.h as well as the platform
+specific header file (e.g. dspbios_osal.h).</p>
+</body></html>
\ No newline at end of file
diff --git a/doc/pte_psp.html b/doc/pte_psp.html
new file mode 100644
index 0000000000000000000000000000000000000000..50fbdc77e5730e7ea7ed346cc920e74e6168d73c
--- /dev/null
+++ b/doc/pte_psp.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html><head><meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"><title>PTE on PSP OS</title></head><body>
+
+
+	<meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8"><title></title><meta name="GENERATOR" content="OpenOffice.org 2.3  (Linux)">
+	
+	
+	<style type="text/css">
+	<!--
+		@page { size: 8.5in 11in; margin: 0.79in }
+		P { margin-bottom: 0.08in }
+		H1 { margin-bottom: 0.08in }
+		H1.western { font-family: "Helvetica"; font-size: 16pt }
+		H1.cjk { font-family: "AR PL ShanHeiSun Uni"; font-size: 16pt }
+		H1.ctl { font-family: "Tahoma"; font-size: 16pt }
+	-->
+	</style>
+
+<p style="margin-bottom: 0in;"><big><big><big><span style="font-weight: bold;">PTE on PSP OS</span></big></big></big></p><p style="margin-bottom: 0in;"><br>
+</p>
+<p style="margin-bottom: 0in;">All PSP OS objects that are created
+require a name to be associated with them.  The name must be unique
+among objects that currently exist.  To accomplish this, any routines
+that allocate OS objects (e.g. <font face="Courier New, monospace">OsMutexCreate</font>)
+keep a static local variable that acts as a counter and is
+incremented every time an object is created.  This value is appended
+to the name of the resource.  For instance &#8220;mutex04&#8221; would be the
+name of the fourth mutex created.</p>
+<p style="margin-bottom: 0in;"><br>
+</p>
+<h1 class="western">Thread creation</h1>
+<p><font face="Courier New, monospace">OsThreadCreate</font>
+allocates a <font face="Courier New, monospace">pspThreadData</font>
+structure that contains a semaphore used for cancelling a thread, the
+thread's entry point and parameters to the thread's entry point.  A
+pointer to this structure is stored as a TLS value.</p>
+<p style="margin-bottom: 0in;"><font face="Courier New, monospace">OsThreadCreate</font>
+calls <font face="Courier New, monospace">sceKernelCreateThread</font>
+with a entry point of <font face="Courier New, monospace">pspStubThreadEntry</font>.
+ The stub entry point retrieves the per thread control structure
+(allocated during <font face="Courier New, monospace">OsThreadCreate</font>)
+and gets the thread's real entry point and parameters and then calls
+the real entry point.</p>
+<p style="margin-bottom: 0in;"><br>
+</p>
+<h1 class="western">Thread Local Storage</h1>
+<p style="margin-bottom: 0in;">Unfortunately, PSP OS does not include
+<b>any</b> kind of thread local storage functionality.  To emulate
+TLS, when a new POSIX thread is created, a structure is allocated to
+contain TLS keys and values.  A pointer to this structure is appended
+to the thread name.  For instance, a new threads name might be 
+&#8220;pthread10_80001234&#8221;, where 0x80001234 is the address of the TLS
+structure.  When a thread wants to access TLS information, it
+retrieves the thread's name from the OS, parses the name to extract
+the pointer and then utilizes the TLS helper library to set or get
+TLS values. 
+</p>
+<p style="margin-bottom: 0in;"><br>
+</p>
+<p style="margin-bottom: 0in;">Unfortunately, this mechanism only
+works for threads that are created through pthread_create; it does
+not work for OS threads that are using pthread calls.  To emulate
+this (at this for one thread) we allocate a single TLS structure
+(like the ones associated with each POSIX thread).  This &#8220;global&#8221;
+TLS structure is used when pthread is called from a non-POSIX OS
+thread.  This introduces the important limitation that pthread calls
+can be made from ONLY ONE non-POSIX OS thread.  Behavior when calling
+from multiple different non-POSIX OS threads is undefined.</p>
+<p style="margin-bottom: 0in;"><br>
+</p>
+<h1 class="western">Mutexes</h1>
+<p style="margin-bottom: 0in;">PSP OS does not supply routines for
+mutexes.  A counting semaphore initialized to 0 is used.</p>
+<p style="margin-bottom: 0in;"><br>
+</p>
+<h1 class="western">Thread Cancellation</h1>
+<p style="margin-bottom: 0in;">Since PSP OS does not natively provide
+a way to break out of blocked operations, this functionality is
+emulated using a cancellation semaphore that is stored in the per
+thread control data.  When the user requests that a thread be
+cancelled (i.e. <font face="Courier New, monospace">OsThreadCancel</font>
+is called) this semaphore is posted to.  In
+<font face="Courier New, monospace">OsSemaphoreCancellablePend</font>,
+the cancellation semaphore as well as the user semaphore are polled
+(rather than blocking) and the routine returns if the cancellation
+semaphore is posted to.  A similar technique is used for
+<font face="Courier New, monospace">OsThreadWaitForEnd</font>.</p>
+</body></html>
\ No newline at end of file
diff --git a/platform/dspbios/pte-config.h b/platform/dspbios/pte-config.h
deleted file mode 100644
index 1591dfe7b25b863d6192e4d26dea56520dd22aa0..0000000000000000000000000000000000000000
--- a/platform/dspbios/pte-config.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* config.h  */
-
-#ifndef PTE_CONFIG_H
-#define PTE_CONFIG_H
-
-#include <time.h>
-
-/*********************************************************************
- * Defaults: see target specific redefinitions below.
- *********************************************************************/
-
-/* We're building the pthreads-win32 library */
-#define PTE_BUILD
-
-#undef PTE_SUPPORT_ASYNC_CANCEL
-
-typedef int pid_t;
-
-struct timespec
-{
-  time_t  tv_sec;
-  long    tv_nsec;   
-};
-
-typedef unsigned int mode_t;
-
-
-struct timeb
-{ 
-  time_t time;
-  unsigned short millitm;
-  short timezone;
-  short dstflag;
-};
-
-#endif
diff --git a/platform/dspbios/pte_test/Configuration1.cdb b/platform/dspbios/pte_test/Configuration1.cdb
index 198d47ddfe9765e4a9e62cddc58a3bd6f83577e0..f9ab9e8936f2757164ad836908aedaf98440fa23 100644
--- a/platform/dspbios/pte_test/Configuration1.cdb
+++ b/platform/dspbios/pte_test/Configuration1.cdb
@@ -75,7 +75,7 @@ type GlobalStatus {
         prop Visible :: 0
         prop Writable :: 1
     }
-    global DATE :: "Fri Apr 04 06:42:26 2008" { 
+    global DATE :: "Fri Apr 04 15:41:02 2008" { 
         prop Type :: "{21455EA3-B96A-11cf-9BFE-0000C0AC14C7}"
         prop Visible :: 0
         prop Writable :: 0
diff --git a/platform/dspbios/pte_test/pte_test.pjt b/platform/dspbios/pte_test/pte_test.pjt
index 1aabab745da29adca413e231fb9ad153e3d4bb2b..fff0f3357af701a7f42271a0991c5cee989b2af5 100644
--- a/platform/dspbios/pte_test/pte_test.pjt
+++ b/platform/dspbios/pte_test/pte_test.pjt
@@ -70,6 +70,7 @@ Source="..\..\..\tests\join0.c"
 Source="..\..\..\tests\join1.c"
 Source="..\..\..\tests\join2.c"
 Source="..\..\..\tests\join3.c"
+Source="..\..\..\tests\join4.c"
 Source="..\..\..\tests\kill1.c"
 Source="..\..\..\tests\mutex1.c"
 Source="..\..\..\tests\mutex1e.c"
@@ -127,6 +128,8 @@ Source="..\..\..\tests\semaphore2.c"
 Source="..\..\..\tests\semaphore3.c"
 Source="..\..\..\tests\semaphore4.c"
 Source="..\..\..\tests\semaphore4t.c"
+Source="..\..\..\tests\semaphore5.c"
+Source="..\..\..\tests\semaphore6.c"
 Source="..\..\..\tests\spin1.c"
 Source="..\..\..\tests\spin2.c"
 Source="..\..\..\tests\spin3.c"
diff --git a/platform/dspbios/pte_types.h b/platform/dspbios/pte_types.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f1260982cf030cebe90d2386e549ca734bf26c9
--- /dev/null
+++ b/platform/dspbios/pte_types.h
@@ -0,0 +1,27 @@
+/* pte_types.h  */
+
+#ifndef PTE_TYPES_H
+#define PTE_TYPES_H
+
+#include <time.h>
+
+typedef int pid_t;
+
+struct timespec
+{
+  time_t  tv_sec;
+  long    tv_nsec;   
+};
+
+typedef unsigned int mode_t;
+
+
+struct timeb
+{ 
+  time_t time;
+  unsigned short millitm;
+  short timezone;
+  short dstflag;
+};
+
+#endif /* PTE_TYPES_H */
diff --git a/platform/psp/Makefile b/platform/psp/Makefile
index e33ab9318b5808b8632f5dd6a65ba614479bd876..f9491e1f6dd1fdd349a72ac7c91391b1d9f5ce4a 100644
--- a/platform/psp/Makefile
+++ b/platform/psp/Makefile
@@ -162,7 +162,7 @@ OS_OBJS = \
 OBJS = $(MUTEX_OBJS) $(MUTEXATTR_OBJS) $(THREAD_OBJS) $(SUPPORT_OBJS) $(TLS_OBJS) $(MISC_OBJS) $(SEM_OBJS) $(BARRIER_OBJS) $(SPIN_OBJS) $(CONDVAR_OBJS) $(RWLOCK_OBJS) $(CANCEL_OBJS) $(OS_OBJS)
 
 INCDIR = 
-CFLAGS = $(GLOBAL_CFLAGS) -G0 -O2 -Wall -g -fno-strict-aliasing -Werror -I../.. -I../helper 
+CFLAGS = $(GLOBAL_CFLAGS) -G0 -O2 -Wall -g -fno-strict-aliasing -I../.. -I../helper 
 CXXFLAGS = $(CFLAGS) -fexceptions -fno-rtti -Werror -D__CLEANUP_CXX
 ASFLAGS = $(CFLAGS)
 
diff --git a/platform/psp/psp_osal.c b/platform/psp/psp_osal.c
index 8b176532c62cd04e4cff45e6edde157d7b08f8e8..a3887a6093446f67921ea3bd1dbae8a310723ac6 100644
--- a/platform/psp/psp_osal.c
+++ b/platform/psp/psp_osal.c
@@ -1 +1 @@
-/*
 * psp_osal.c
 *
 * Description:
 *
 * --------------------------------------------------------------------------
 *
 *      Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
 *      Copyright(C) 2008 Jason Schmidlapp
 *
 *      Contact Email: jschmidlapp@users.sourceforge.net
 *
 *      This library is free software; you can redistribute it and/or
 *      modify it under the terms of the GNU Lesser General Public
 *      License as published by the Free Software Foundation; either
 *      version 2 of the License, or (at your option) any later version.
 *
 *      This library is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *      Lesser General Public License for more details.
 *
 *      You should have received a copy of the GNU Lesser General Public
 *      License along with this library in the file COPYING.LIB;
 *      if not, write to the Free Software Foundation, Inc.,
 *      59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pspkerror.h>
#include "pte_osal.h"
#include "pthread.h"
#include "tls-helper.h"

/* For ftime */
#include <sys/time.h>
#include <sys/types.h>
#include <sys/timeb.h>

#define MAX_PSP_UID 2048 // SWAG

#define DEFAULT_STACK_SIZE_BYTES 4096

#define PSP_MAX_TLS 32

#if 1
#define PSP_DEBUG(x) printf(x)
#else
#define PSP_DEBUG(x)
#endif

/* TLS key used to access pspThreadData struct for reach thread. */
static unsigned int threadDataKey;

/*
 * Data stored on a per-thread basis - allocated in pte_osThreadCreate
 * and freed in pte_osThreadDelete.
 */
typedef struct pspThreadData
  {
    /* Entry point and parameters to thread's main function */
    pte_osThreadEntryPoint entryPoint;
    void * argv;

    /* Semaphore used for cancellation.  Posted to by pte_osThreadCancel, 
       polled in pte_osSemaphoreCancellablePend */
    SceUID cancelSem;

  } pspThreadData;


/* Structure used to emulate TLS on non-POSIX threads.  
 * This limits us to one non-POSIX thread that can
 * call pthread functions. */
static void *globalTls;

/* Helper functions */
static pspThreadData *getThreadData(SceUID threadHandle);
static void *getTlsStructFromThread(SceUID thid);

/* A new thread's stub entry point.  It retrieves the real entry point from the per thread control
 * data as well as any parameters to this function, and then calls the entry point.
 */
int pspStubThreadEntry (unsigned int argc, void *argv)
{
  int result;
  pspThreadData *pThreadData;

  pThreadData = getThreadData(sceKernelGetThreadId());

  result = (*(pThreadData->entryPoint))(pThreadData->argv);

  return result;
}

/****************************************************************************
 *
 * Initialization
 *
 ***************************************************************************/

pte_osResult pte_osInit(void)
{
  pte_osResult result;
  pspThreadData *pThreadData;
  char cancelSemName[64];

  /* Allocate and initialize TLS support */
  result = pteTlsGlobalInit(PSP_MAX_TLS);

  if (result == PTE_OS_OK)
  {

    /* Allocate a key that we use to store control information (e.g. cancellation semaphore) per thread */
    result = pteTlsAlloc(&threadDataKey);

    if (result == PTE_OS_OK)
      {

	/* Initialize the structure used to emulate TLS for 
	 * non-POSIX threads 
	 */
	globalTls = pteTlsThreadInit();

	/* Also create a "thread data" structure for a single non-POSIX thread. */

	/* Allocate some memory for our per-thread control data.  We use this for:
	 * 1. Entry point and parameters for the user thread's main function.
	 * 2. Semaphore used for thread cancellation.
	 */
	pThreadData = (pspThreadData *) malloc(sizeof(pspThreadData));
	
	if (pThreadData == NULL)
	  {
	    result = PTE_OS_NO_RESOURCES;
	  }
	else
	  {

	    /* Save a pointer to our per-thread control data as a TLS value */
	    pteTlsSetValue(globalTls, threadDataKey, pThreadData);
	
	    /* Create a semaphore used to cancel threads */
	    snprintf(cancelSemName, sizeof(cancelSemName), "pthread_cancelSemGlobal");
	    
	    pThreadData->cancelSem = sceKernelCreateSema(cancelSemName,
							 0,          /* attributes (default) */
							 0,          /* initial value        */
							 255,        /* maximum value        */
							 0);         /* options (default)    */
	    result = PTE_OS_OK;
	  }
      }
  }

  return result;
}

/****************************************************************************
 *
 * Threads
 *
 ***************************************************************************/

pte_osResult pte_osThreadCreate(pte_osThreadEntryPoint entryPoint,
                                int stackSize,
                                int initialPriority,
                                void *argv,
                                pte_osThreadHandle* ppte_osThreadHandle)
{
  char threadName[64];
  char cancelSemName[64];
  static int threadNum = 1;
  int pspAttr;
  void *pTls;
  SceUID threadId;
  pte_osResult result;
  pspThreadData *pThreadData;

  if (threadNum++ > MAX_PSP_UID)
    {
      threadNum = 0;
    }

  /* Make sure that the stack we're going to allocate is big enough */
  if (stackSize < DEFAULT_STACK_SIZE_BYTES)
    {
      stackSize = DEFAULT_STACK_SIZE_BYTES;
    }

  /* Allocate TLS structure for this thread. */
  pTls = pteTlsThreadInit();
  if (pTls == NULL)
    {
      PSP_DEBUG("pteTlsThreadInit: PTE_OS_NO_RESOURCES\n");
      result = PTE_OS_NO_RESOURCES;
      goto FAIL0;
    }

  /* Allocate some memory for our per-thread control data.  We use this for:
   * 1. Entry point and parameters for the user thread's main function.
   * 2. Semaphore used for thread cancellation.
   */
  pThreadData = (pspThreadData *) malloc(sizeof(pspThreadData));

  if (pThreadData == NULL)
    {
      pteTlsThreadDestroy(pTls);

      PSP_DEBUG("malloc(pspThreadData): PTE_OS_NO_RESOURCES\n");
      result = PTE_OS_NO_RESOURCES;
      goto FAIL0;
    }

  /* Save a pointer to our per-thread control data as a TLS value */
  pteTlsSetValue(pTls, threadDataKey, pThreadData);

  pThreadData->entryPoint = entryPoint;
  pThreadData->argv = argv;

  /* Create a semaphore used to cancel threads */
  snprintf(cancelSemName, sizeof(cancelSemName), "pthread_cancelSem%04d", threadNum);

  pThreadData->cancelSem = sceKernelCreateSema(cancelSemName,
                           0,          /* attributes (default) */
                           0,          /* initial value        */
                           255,        /* maximum value        */
                           0);         /* options (default)    */


  /* In order to emulate TLS functionality, we append the address of the TLS structure that we
   * allocated above to the thread's name.  To set or get TLS values for this thread, the user
   * needs to get the name of the thread from the OS and then parse the name to extract
   * a pointer to the TLS structure.
   */
  snprintf(threadName, sizeof(threadName), "pthread%04d__%x", threadNum, (unsigned int) pTls);

  pspAttr = 0;

  //  printf("%s %p %d %d %d\n",threadName, pspStubThreadEntry, initialPriority, stackSize, pspAttr);
  threadId = sceKernelCreateThread(threadName,
                                   pspStubThreadEntry,
                                   initialPriority,
                                   stackSize,
                                   pspAttr,
                                   NULL);

  if (threadId == (SceUID) SCE_KERNEL_ERROR_NO_MEMORY)
    {
      free(pThreadData);
      pteTlsThreadDestroy(pTls);

      PSP_DEBUG("sceKernelCreateThread: PTE_OS_NO_RESOURCES\n");
      result =  PTE_OS_NO_RESOURCES;
    }
  else if (threadId < 0)
    {
      free(pThreadData);
      pteTlsThreadDestroy(pTls);

      PSP_DEBUG("sceKernelCreateThread: PTE_OS_GENERAL_FAILURE\n");
      result = PTE_OS_GENERAL_FAILURE;
    }
  else
    {
      *ppte_osThreadHandle = threadId;
      result = PTE_OS_OK;
    }

FAIL0:
  return result;
}


pte_osResult pte_osThreadStart(pte_osThreadHandle osThreadHandle)
{
  sceKernelStartThread(osThreadHandle, 0, NULL);

  return PTE_OS_OK;
}


pte_osResult pte_osThreadDelete(pte_osThreadHandle handle)
{
  pspThreadData *pThreadData;
  void *pTls;

  pTls = getTlsStructFromThread(handle);

  pThreadData = getThreadData(handle);

  sceKernelDeleteSema(pThreadData->cancelSem);  

  free(pThreadData);

  pteTlsThreadDestroy(pTls);

  sceKernelDeleteThread(handle);

  return PTE_OS_OK;
}

pte_osResult pte_osThreadExitAndDelete(pte_osThreadHandle handle)
{
  pte_osThreadDelete(handle);

  sceKernelExitDeleteThread(0);

  return PTE_OS_OK;
}

void pte_osThreadExit()
{
  sceKernelExitThread(0);
}

/*
 * This has to be cancellable, so we can't just call sceKernelWaitThreadEnd.
 * Instead, poll on this in a loop, like we do for a cancellable semaphore.
 */
pte_osResult pte_osThreadWaitForEnd(pte_osThreadHandle threadHandle)
{
  pte_osResult result;
  pspThreadData *pThreadData;

  pThreadData = getThreadData(sceKernelGetThreadId());

  while (1)
    {
      SceKernelThreadRunStatus info;

      /* Poll task to see if it has ended */
      memset(&info,0,sizeof(info));
      info.size = sizeof(info);
      sceKernelReferThreadRunStatus(threadHandle, &info);      

      if (info.status == PSP_THREAD_STOPPED)
        {
	  /* Thread has ended */
          result = PTE_OS_OK;
          break;
        }
      else
        {
          SceKernelSemaInfo semInfo;

          if (pThreadData != NULL)
            {
	      SceUID osResult;
	      
              osResult = sceKernelReferSemaStatus(pThreadData->cancelSem, &semInfo);
	      
	      if (osResult == SCE_KERNEL_ERROR_OK)
		{
		  if (semInfo.currentCount > 0)
		    {
		      result = PTE_OS_INTERRUPTED;
		      break;
		    }
		  else
		    {
		      /* Nothing found and not timed out yet; let's yield so we're not
		       * in busy loop.
		       */
		      sceKernelDelayThread(POLLING_DELAY_IN_us);
		    }
		}
	      else
		{
		  result = PTE_OS_GENERAL_FAILURE;
		  break;
		}
            }
        }
    }


  return result;
}

pte_osThreadHandle pte_osThreadGetHandle(void)
{
  return sceKernelGetThreadId();
}

int pte_osThreadGetPriority(pte_osThreadHandle threadHandle)
{
  SceKernelThreadInfo thinfo;

  thinfo.size = sizeof(SceKernelThreadInfo);

  sceKernelReferThreadStatus(threadHandle, &thinfo);

  return thinfo.currentPriority;
}

pte_osResult pte_osThreadSetPriority(pte_osThreadHandle threadHandle, int newPriority)
{
  sceKernelChangeThreadPriority(threadHandle, newPriority);
  return PTE_OS_OK;
}

pte_osResult pte_osThreadCancel(pte_osThreadHandle threadHandle)
{
  SceUID osResult;
  pte_osResult result;
  pspThreadData *pThreadData;

  pThreadData = getThreadData(threadHandle);

  osResult = sceKernelSignalSema(pThreadData->cancelSem, 1);

  if (osResult == SCE_KERNEL_ERROR_OK)
    {
      result = PTE_OS_OK;
    }
  else
    {
      result = PTE_OS_GENERAL_FAILURE;
    }

  return result;
}


pte_osResult pte_osThreadCheckCancel(pte_osThreadHandle threadHandle)
{
  pspThreadData *pThreadData;
  SceKernelSemaInfo semInfo;
  SceUID osResult;
  pte_osResult result;

  pThreadData = getThreadData(threadHandle);

  if (pThreadData != NULL)
    {
      osResult = sceKernelReferSemaStatus(pThreadData->cancelSem, &semInfo);

      if (osResult == SCE_KERNEL_ERROR_OK)
	{
	  if (semInfo.currentCount > 0)
	    {
	      result = PTE_OS_INTERRUPTED;
	    }
	  else
	    {
	      result = PTE_OS_OK;
	    }
	}
      else
	{
	  /* sceKernelReferSemaStatus returned an error */
	  result = PTE_OS_GENERAL_FAILURE;
	}
    }
  else
    {
      /* For some reason, we couldn't get thread data */
      result = PTE_OS_GENERAL_FAILURE;
    }

  return result;
}

void pte_osThreadSleep(unsigned int msecs)
{
  sceKernelDelayThread(msecs*1000);
}

int pte_osThreadGetMinPriority()
{
  return 17;
}

int pte_osThreadGetMaxPriority()
{
  return 30;
}

int pte_osThreadGetDefaultPriority()
{
  return 18;
}

/****************************************************************************
 *
 * Mutexes
 *
 ****************************************************************************/

pte_osResult pte_osMutexCreate(pte_osMutexHandle *pHandle)
{
  static int mutexCtr = 0;
  char mutexName[32];
  pte_osMutexHandle handle;

  if (mutexCtr++ > MAX_PSP_UID)
    {
      mutexCtr = 0;
    }

  snprintf(mutexName,sizeof(mutexName),"mutex%d",mutexCtr);

  handle = sceKernelCreateSema(mutexName,
                               0,          /* attributes (default) */
                               1,          /* initial value        */
                               1,          /* maximum value        */
                               0);         /* options (default)    */

  *pHandle = handle;

  return PTE_OS_OK;
}

pte_osResult pte_osMutexDelete(pte_osMutexHandle handle)
{
  sceKernelDeleteSema(handle);

  return PTE_OS_OK;
}



pte_osResult pte_osMutexLock(pte_osMutexHandle handle)
{
  sceKernelWaitSema(handle, 1, NULL);

  return PTE_OS_OK;
}

pte_osResult pte_osMutexTimedLock(pte_osMutexHandle handle, unsigned int timeoutMsecs)
{
  pte_osResult result;
  SceUInt timeoutUsecs = timeoutMsecs*1000;

  int status = sceKernelWaitSema(handle, 1, &timeoutUsecs);

  if (status < 0)
    {
      // Assume that any error from sceKernelWaitSema was due to a timeout
      result = PTE_OS_TIMEOUT;
    }
  else
    {
      result = PTE_OS_OK;
    }

  return result;
}


pte_osResult pte_osMutexUnlock(pte_osMutexHandle handle)
{
  sceKernelSignalSema(handle, 1);

  return PTE_OS_OK;
}

/****************************************************************************
 *
 * Semaphores
 *
 ***************************************************************************/

pte_osResult pte_osSemaphoreCreate(int initialValue, pte_osSemaphoreHandle *pHandle)
{
  pte_osSemaphoreHandle handle;
  static int semCtr = 0;
  char semName[32];

  if (semCtr++ > MAX_PSP_UID)
    {
      semCtr = 0;
    }

  snprintf(semName,sizeof(semName),"pthread_sem%d",semCtr);

  handle = sceKernelCreateSema(semName,
                               0,              /* attributes (default) */
                               initialValue,   /* initial value        */
                               SEM_VALUE_MAX,  /* maximum value        */
                               0);             /* options (default)    */

  *pHandle = handle;

  return PTE_OS_OK;
}

pte_osResult pte_osSemaphoreDelete(pte_osSemaphoreHandle handle)
{
  sceKernelDeleteSema(handle);

  return PTE_OS_OK;
}


pte_osResult pte_osSemaphorePost(pte_osSemaphoreHandle handle, int count)
{
  sceKernelSignalSema(handle, count);

  return PTE_OS_OK;
}

pte_osResult pte_osSemaphorePend(pte_osSemaphoreHandle handle, unsigned int *pTimeoutMsecs)
{
  unsigned int timeoutUsecs;
  unsigned int *pTimeoutUsecs;
  SceUInt result;
  pte_osResult osResult;

  if (pTimeoutMsecs == NULL)
    {
      pTimeoutUsecs = NULL;
    }
  else
    {
      timeoutUsecs = *pTimeoutMsecs * 1000;
      pTimeoutUsecs = &timeoutUsecs;
    }

  result = sceKernelWaitSema(handle, 1, pTimeoutUsecs);

  if (result == SCE_KERNEL_ERROR_OK)
    {
      osResult = PTE_OS_OK;
    }
  else if (result == SCE_KERNEL_ERROR_WAIT_TIMEOUT)
    {
      osResult = PTE_OS_TIMEOUT;
    }
  else
    {
      osResult = PTE_OS_GENERAL_FAILURE;
    }

  return osResult;
}


/*
 * Pend on a semaphore- and allow the pend to be cancelled.
 *
 * PSP OS provides no functionality to asynchronously interrupt a blocked call.  We simulte
 * this by polling on the main semaphore and the cancellation semaphore and sleeping in a loop.
 */
pte_osResult pte_osSemaphoreCancellablePend(pte_osSemaphoreHandle semHandle, unsigned int *pTimeout)
{
  pspThreadData *pThreadData;

  pThreadData = getThreadData(sceKernelGetThreadId());

  clock_t start_time;
  pte_osResult result =  PTE_OS_OK;
  unsigned int timeout;
  unsigned char timeoutEnabled;

  start_time = clock();

  // clock() is in microseconds, timeout as passed in was in milliseconds
  if (pTimeout == NULL)
    {
      timeout = 0;
      timeoutEnabled = 0;
    }
  else
    {
      timeout = *pTimeout * 1000;
      timeoutEnabled = 1;
    }

  while (1)
    {
      SceUInt semTimeout;
      int status;

      /* Poll semaphore */
      semTimeout = 0;
      status = sceKernelWaitSema(semHandle, 1, &semTimeout);

      if (status == SCE_KERNEL_ERROR_OK)
        {
          /* User semaphore posted to */
          result = PTE_OS_OK;
          break;
        }
      else if ((timeoutEnabled) && ((clock() - start_time) > timeout))
        {
          /* Timeout expired */
          result = PTE_OS_TIMEOUT;
          break;
        }
      else
        {
          SceKernelSemaInfo semInfo;

          if (pThreadData != NULL)
            {
	      SceUID osResult;
	      
              osResult = sceKernelReferSemaStatus(pThreadData->cancelSem, &semInfo);
	      
	      if (osResult == SCE_KERNEL_ERROR_OK)
		{
		  if (semInfo.currentCount > 0)
		    {
		      result = PTE_OS_INTERRUPTED;
		      break;
		    }
		  else
		    {
		      /* Nothing found and not timed out yet; let's yield so we're not
		       * in busy loop.
		       */
		      sceKernelDelayThread(POLLING_DELAY_IN_us);
		    }
		}
	      else
		{
		  result = PTE_OS_GENERAL_FAILURE;
		  break;
		}
            }
        }
    }

  return result;
}


/****************************************************************************
 *
 * Atomic Operations
 *
 ***************************************************************************/

int pte_osAtomicExchange(int *ptarg, int val)
{
  int intc = pspSdkDisableInterrupts();
  int origVal;

  origVal = *ptarg;

  *ptarg = val;

  pspSdkEnableInterrupts(intc);

  return origVal;

}

int pte_osAtomicCompareExchange(int *pdest, int exchange, int comp)
{
  int intc = pspSdkDisableInterrupts();
  int origVal;

  origVal = *pdest;

  if (*pdest == comp)
    {
      *pdest = exchange;
    }

  pspSdkEnableInterrupts(intc);

  return origVal;
}


int pte_osAtomicExchangeAdd(int volatile* pAddend, int value)
{
  int origVal;
  int intc = pspSdkDisableInterrupts();

  origVal = *pAddend;

  *pAddend += value;

  pspSdkEnableInterrupts(intc);

  return origVal;
}

int pte_osAtomicDecrement(int *pdest)
{
  int val;

  int intc = pspSdkDisableInterrupts();

  (*pdest)--;
  val = *pdest;

  pspSdkEnableInterrupts(intc);

  return val;
}

int pte_osAtomicIncrement(int *pdest)
{
  int val;

  int intc = pspSdkDisableInterrupts();

  (*pdest)++;
  val = *pdest;

  pspSdkEnableInterrupts(intc);

  return val;
}

/****************************************************************************
 *
 * Helper functions
 *
 ***************************************************************************/

static pspThreadData *getThreadData(SceUID threadHandle)
{
  pspThreadData *pThreadData;
  void *pTls;

  pTls = getTlsStructFromThread(threadHandle);

  pThreadData = (pspThreadData *) pteTlsGetValue(pTls, threadDataKey);

  return pThreadData;
}

static void *getTlsStructFromThread(SceUID thid)
{
  SceKernelThreadInfo thinfo;
  unsigned int ptr;
  unsigned int thrNum;
  void *pTls;
  int numMatches;


  thinfo.size = sizeof(SceKernelThreadInfo);

  sceKernelReferThreadStatus(thid, &thinfo);

  numMatches = sscanf(thinfo.name,"pthread%04d__%x", &thrNum, &ptr);

  /* If we were called from a pthread, use the TLS allocated when the thread
   * was created.  Otherwise, we were called from a non-pthread, so use the
   * "global".  This is a pretty bad hack, but necessary due to lack of TLS on PSP.
   */
  if (numMatches == 2)
    {
      pTls = (void *) ptr;
    }
  else
    {
      pTls = globalTls;
    }

  return pTls;
}

/****************************************************************************
 *
 * Thread Local Storage
 *
 ***************************************************************************/

pte_osResult pte_osTlsSetValue(unsigned int key, void * value)
{
  void *pTls;

  pTls = getTlsStructFromThread(sceKernelGetThreadId());

  return pteTlsSetValue(pTls, key, value);
}

void * pte_osTlsGetValue(unsigned int index)
{

  void *pTls;

  pTls = getTlsStructFromThread(sceKernelGetThreadId());

  return (void *) pteTlsGetValue(pTls, index);

}


pte_osResult pte_osTlsAlloc(unsigned int *pKey)
{
  void * pTls;

  pTls = getTlsStructFromThread(sceKernelGetThreadId());

  return pteTlsAlloc(pKey);

}

pte_osResult pte_osTlsFree(unsigned int index)
{
  return pteTlsFree(index);
}

/****************************************************************************
 *
 * Miscellaneous
 *
 ***************************************************************************/

int ftime(struct timeb *tb)
{
  struct timeval tv;
  struct timezone tz;

  gettimeofday(&tv, &tz);

  tb->time = tv.tv_sec;
  tb->millitm = tv.tv_usec / 1000;
  tb->timezone = tz.tz_minuteswest;
  tb->dstflag = tz.tz_dsttime;

  return 0;
}
\ No newline at end of file
+/*
 * psp_osal.c
 *
 * Description:
 *
 * --------------------------------------------------------------------------
 *
 *      Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
 *      Copyright(C) 2008 Jason Schmidlapp
 *
 *      Contact Email: jschmidlapp@users.sourceforge.net
 *
 *      This library is free software; you can redistribute it and/or
 *      modify it under the terms of the GNU Lesser General Public
 *      License as published by the Free Software Foundation; either
 *      version 2 of the License, or (at your option) any later version.
 *
 *      This library is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *      Lesser General Public License for more details.
 *
 *      You should have received a copy of the GNU Lesser General Public
 *      License along with this library in the file COPYING.LIB;
 *      if not, write to the Free Software Foundation, Inc.,
 *      59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pspkerror.h>
#include "pte_osal.h"
#include "pthread.h"
#include "tls-helper.h"

/* For ftime */
#include <sys/time.h>
#include <sys/types.h>
#include <sys/timeb.h>

#define MAX_PSP_UID 2048 // SWAG

#define DEFAULT_STACK_SIZE_BYTES 4096

#define PSP_MAX_TLS 32

#if 1
#define PSP_DEBUG(x) printf(x)
#else
#define PSP_DEBUG(x)
#endif

/* TLS key used to access pspThreadData struct for reach thread. */
static unsigned int threadDataKey;

/*
 * Data stored on a per-thread basis - allocated in pte_osThreadCreate
 * and freed in pte_osThreadDelete.
 */
typedef struct pspThreadData
  {
    /* Entry point and parameters to thread's main function */
    pte_osThreadEntryPoint entryPoint;
    void * argv;

    /* Semaphore used for cancellation.  Posted to by pte_osThreadCancel, 
       polled in pte_osSemaphoreCancellablePend */
    SceUID cancelSem;

  } pspThreadData;


/* Structure used to emulate TLS on non-POSIX threads.  
 * This limits us to one non-POSIX thread that can
 * call pthread functions. */
static void *globalTls;

/* Helper functions */
static pspThreadData *getThreadData(SceUID threadHandle);
static void *getTlsStructFromThread(SceUID thid);

/* A new thread's stub entry point.  It retrieves the real entry point from the per thread control
 * data as well as any parameters to this function, and then calls the entry point.
 */
int pspStubThreadEntry (unsigned int argc, void *argv)
{
  int result;
  pspThreadData *pThreadData;

  pThreadData = getThreadData(sceKernelGetThreadId());

  result = (*(pThreadData->entryPoint))(pThreadData->argv);

  return result;
}

/****************************************************************************
 *
 * Initialization
 *
 ***************************************************************************/

pte_osResult pte_osInit(void)
{
  pte_osResult result;
  pspThreadData *pThreadData;
  char cancelSemName[64];

  /* Allocate and initialize TLS support */
  result = pteTlsGlobalInit(PSP_MAX_TLS);

  if (result == PTE_OS_OK)
  {

    /* Allocate a key that we use to store control information (e.g. cancellation semaphore) per thread */
    result = pteTlsAlloc(&threadDataKey);

    if (result == PTE_OS_OK)
      {

	/* Initialize the structure used to emulate TLS for 
	 * non-POSIX threads 
	 */
	globalTls = pteTlsThreadInit();

	/* Also create a "thread data" structure for a single non-POSIX thread. */

	/* Allocate some memory for our per-thread control data.  We use this for:
	 * 1. Entry point and parameters for the user thread's main function.
	 * 2. Semaphore used for thread cancellation.
	 */
	pThreadData = (pspThreadData *) malloc(sizeof(pspThreadData));
	
	if (pThreadData == NULL)
	  {
	    result = PTE_OS_NO_RESOURCES;
	  }
	else
	  {

	    /* Save a pointer to our per-thread control data as a TLS value */
	    pteTlsSetValue(globalTls, threadDataKey, pThreadData);
	
	    /* Create a semaphore used to cancel threads */
	    snprintf(cancelSemName, sizeof(cancelSemName), "pthread_cancelSemGlobal");
	    
	    pThreadData->cancelSem = sceKernelCreateSema(cancelSemName,
							 0,          /* attributes (default) */
							 0,          /* initial value        */
							 255,        /* maximum value        */
							 0);         /* options (default)    */
	    result = PTE_OS_OK;
	  }
      }
  }

  return result;
}

/****************************************************************************
 *
 * Threads
 *
 ***************************************************************************/

pte_osResult pte_osThreadCreate(pte_osThreadEntryPoint entryPoint,
                                int stackSize,
                                int initialPriority,
                                void *argv,
                                pte_osThreadHandle* ppte_osThreadHandle)
{
  char threadName[64];
  char cancelSemName[64];
  static int threadNum = 1;
  int pspAttr;
  void *pTls;
  SceUID threadId;
  pte_osResult result;
  pspThreadData *pThreadData;

  if (threadNum++ > MAX_PSP_UID)
    {
      threadNum = 0;
    }

  /* Make sure that the stack we're going to allocate is big enough */
  if (stackSize < DEFAULT_STACK_SIZE_BYTES)
    {
      stackSize = DEFAULT_STACK_SIZE_BYTES;
    }

  /* Allocate TLS structure for this thread. */
  pTls = pteTlsThreadInit();
  if (pTls == NULL)
    {
      PSP_DEBUG("pteTlsThreadInit: PTE_OS_NO_RESOURCES\n");
      result = PTE_OS_NO_RESOURCES;
      goto FAIL0;
    }

  /* Allocate some memory for our per-thread control data.  We use this for:
   * 1. Entry point and parameters for the user thread's main function.
   * 2. Semaphore used for thread cancellation.
   */
  pThreadData = (pspThreadData *) malloc(sizeof(pspThreadData));

  if (pThreadData == NULL)
    {
      pteTlsThreadDestroy(pTls);

      PSP_DEBUG("malloc(pspThreadData): PTE_OS_NO_RESOURCES\n");
      result = PTE_OS_NO_RESOURCES;
      goto FAIL0;
    }

  /* Save a pointer to our per-thread control data as a TLS value */
  pteTlsSetValue(pTls, threadDataKey, pThreadData);

  pThreadData->entryPoint = entryPoint;
  pThreadData->argv = argv;

  /* Create a semaphore used to cancel threads */
  snprintf(cancelSemName, sizeof(cancelSemName), "pthread_cancelSem%04d", threadNum);

  pThreadData->cancelSem = sceKernelCreateSema(cancelSemName,
                           0,          /* attributes (default) */
                           0,          /* initial value        */
                           255,        /* maximum value        */
                           0);         /* options (default)    */


  /* In order to emulate TLS functionality, we append the address of the TLS structure that we
   * allocated above to the thread's name.  To set or get TLS values for this thread, the user
   * needs to get the name of the thread from the OS and then parse the name to extract
   * a pointer to the TLS structure.
   */
  snprintf(threadName, sizeof(threadName), "pthread%04d__%x", threadNum, (unsigned int) pTls);

  pspAttr = 0;

  //  printf("%s %p %d %d %d\n",threadName, pspStubThreadEntry, initialPriority, stackSize, pspAttr);
  threadId = sceKernelCreateThread(threadName,
                                   pspStubThreadEntry,
                                   initialPriority,
                                   stackSize,
                                   pspAttr,
                                   NULL);

  if (threadId == (SceUID) SCE_KERNEL_ERROR_NO_MEMORY)
    {
      free(pThreadData);
      pteTlsThreadDestroy(pTls);

      PSP_DEBUG("sceKernelCreateThread: PTE_OS_NO_RESOURCES\n");
      result =  PTE_OS_NO_RESOURCES;
    }
  else if (threadId < 0)
    {
      free(pThreadData);
      pteTlsThreadDestroy(pTls);

      PSP_DEBUG("sceKernelCreateThread: PTE_OS_GENERAL_FAILURE\n");
      result = PTE_OS_GENERAL_FAILURE;
    }
  else
    {
      *ppte_osThreadHandle = threadId;
      result = PTE_OS_OK;
    }

FAIL0:
  return result;
}


pte_osResult pte_osThreadStart(pte_osThreadHandle osThreadHandle)
{
  sceKernelStartThread(osThreadHandle, 0, NULL);

  return PTE_OS_OK;
}


pte_osResult pte_osThreadDelete(pte_osThreadHandle handle)
{
  pspThreadData *pThreadData;
  void *pTls;

  pTls = getTlsStructFromThread(handle);

  pThreadData = getThreadData(handle);

  sceKernelDeleteSema(pThreadData->cancelSem);  

  free(pThreadData);

  pteTlsThreadDestroy(pTls);

  sceKernelDeleteThread(handle);

  return PTE_OS_OK;
}

pte_osResult pte_osThreadExitAndDelete(pte_osThreadHandle handle)
{
  pte_osThreadDelete(handle);

  sceKernelExitDeleteThread(0);

  return PTE_OS_OK;
}

void pte_osThreadExit()
{
  sceKernelExitThread(0);
}

/*
 * This has to be cancellable, so we can't just call sceKernelWaitThreadEnd.
 * Instead, poll on this in a loop, like we do for a cancellable semaphore.
 */
pte_osResult pte_osThreadWaitForEnd(pte_osThreadHandle threadHandle)
{
  pte_osResult result;
  pspThreadData *pThreadData;

  pThreadData = getThreadData(sceKernelGetThreadId());

  while (1)
    {
      SceKernelThreadRunStatus info;

      /* Poll task to see if it has ended */
      memset(&info,0,sizeof(info));
      info.size = sizeof(info);
      sceKernelReferThreadRunStatus(threadHandle, &info);      

      if (info.status == PSP_THREAD_STOPPED)
        {
	  /* Thread has ended */
          result = PTE_OS_OK;
          break;
        }
      else
        {
          SceKernelSemaInfo semInfo;

          if (pThreadData != NULL)
            {
	      SceUID osResult;
	      
              osResult = sceKernelReferSemaStatus(pThreadData->cancelSem, &semInfo);
	      
	      if (osResult == SCE_KERNEL_ERROR_OK)
		{
		  if (semInfo.currentCount > 0)
		    {
		      result = PTE_OS_INTERRUPTED;
		      break;
		    }
		  else
		    {
		      /* Nothing found and not timed out yet; let's yield so we're not
		       * in busy loop.
		       */
		      sceKernelDelayThread(POLLING_DELAY_IN_us);
		    }
		}
	      else
		{
		  result = PTE_OS_GENERAL_FAILURE;
		  break;
		}
            }
        }
    }


  return result;
}

pte_osThreadHandle pte_osThreadGetHandle(void)
{
  return sceKernelGetThreadId();
}

int pte_osThreadGetPriority(pte_osThreadHandle threadHandle)
{
  SceKernelThreadInfo thinfo;

  thinfo.size = sizeof(SceKernelThreadInfo);

  sceKernelReferThreadStatus(threadHandle, &thinfo);

  return thinfo.currentPriority;
}

pte_osResult pte_osThreadSetPriority(pte_osThreadHandle threadHandle, int newPriority)
{
  sceKernelChangeThreadPriority(threadHandle, newPriority);
  return PTE_OS_OK;
}

pte_osResult pte_osThreadCancel(pte_osThreadHandle threadHandle)
{
  SceUID osResult;
  pte_osResult result;
  pspThreadData *pThreadData;

  pThreadData = getThreadData(threadHandle);

  osResult = sceKernelSignalSema(pThreadData->cancelSem, 1);

  if (osResult == SCE_KERNEL_ERROR_OK)
    {
      result = PTE_OS_OK;
    }
  else
    {
      result = PTE_OS_GENERAL_FAILURE;
    }

  return result;
}


pte_osResult pte_osThreadCheckCancel(pte_osThreadHandle threadHandle)
{
  pspThreadData *pThreadData;
  SceKernelSemaInfo semInfo;
  SceUID osResult;
  pte_osResult result;

  pThreadData = getThreadData(threadHandle);

  if (pThreadData != NULL)
    {
      osResult = sceKernelReferSemaStatus(pThreadData->cancelSem, &semInfo);

      if (osResult == SCE_KERNEL_ERROR_OK)
	{
	  if (semInfo.currentCount > 0)
	    {
	      result = PTE_OS_INTERRUPTED;
	    }
	  else
	    {
	      result = PTE_OS_OK;
	    }
	}
      else
	{
	  /* sceKernelReferSemaStatus returned an error */
	  result = PTE_OS_GENERAL_FAILURE;
	}
    }
  else
    {
      /* For some reason, we couldn't get thread data */
      result = PTE_OS_GENERAL_FAILURE;
    }

  return result;
}

void pte_osThreadSleep(unsigned int msecs)
{
  sceKernelDelayThread(msecs*1000);
}

int pte_osThreadGetMinPriority()
{
  return 17;
}

int pte_osThreadGetMaxPriority()
{
  return 30;
}

int pte_osThreadGetDefaultPriority()
{
  return 18;
}

/****************************************************************************
 *
 * Mutexes
 *
 ****************************************************************************/

pte_osResult pte_osMutexCreate(pte_osMutexHandle *pHandle)
{
  static int mutexCtr = 0;
  char mutexName[32];
  pte_osMutexHandle handle;

  if (mutexCtr++ > MAX_PSP_UID)
    {
      mutexCtr = 0;
    }

  snprintf(mutexName,sizeof(mutexName),"mutex%d",mutexCtr);

  handle = sceKernelCreateSema(mutexName,
                               0,          /* attributes (default) */
                               1,          /* initial value        */
                               1,          /* maximum value        */
                               0);         /* options (default)    */

  *pHandle = handle;

  return PTE_OS_OK;
}

pte_osResult pte_osMutexDelete(pte_osMutexHandle handle)
{
  sceKernelDeleteSema(handle);

  return PTE_OS_OK;
}



pte_osResult pte_osMutexLock(pte_osMutexHandle handle)
{
  sceKernelWaitSema(handle, 1, NULL);

  return PTE_OS_OK;
}

pte_osResult pte_osMutexTimedLock(pte_osMutexHandle handle, unsigned int timeoutMsecs)
{
  pte_osResult result;
  SceUInt timeoutUsecs = timeoutMsecs*1000;

  int status = sceKernelWaitSema(handle, 1, &timeoutUsecs);

  if (status < 0)
    {
      // Assume that any error from sceKernelWaitSema was due to a timeout
      result = PTE_OS_TIMEOUT;
    }
  else
    {
      result = PTE_OS_OK;
    }

  return result;
}


pte_osResult pte_osMutexUnlock(pte_osMutexHandle handle)
{
  sceKernelSignalSema(handle, 1);

  return PTE_OS_OK;
}

/****************************************************************************
 *
 * Semaphores
 *
 ***************************************************************************/

pte_osResult pte_osSemaphoreCreate(int initialValue, pte_osSemaphoreHandle *pHandle)
{
  pte_osSemaphoreHandle handle;
  static int semCtr = 0;
  char semName[32];

  if (semCtr++ > MAX_PSP_UID)
    {
      semCtr = 0;
    }

  snprintf(semName,sizeof(semName),"pthread_sem%d",semCtr);

  handle = sceKernelCreateSema(semName,
                               0,              /* attributes (default) */
                               initialValue,   /* initial value        */
                               SEM_VALUE_MAX,  /* maximum value        */
                               0);             /* options (default)    */

  *pHandle = handle;

  return PTE_OS_OK;
}

pte_osResult pte_osSemaphoreDelete(pte_osSemaphoreHandle handle)
{
  sceKernelDeleteSema(handle);

  return PTE_OS_OK;
}


pte_osResult pte_osSemaphorePost(pte_osSemaphoreHandle handle, int count)
{
  sceKernelSignalSema(handle, count);

  return PTE_OS_OK;
}

pte_osResult pte_osSemaphorePend(pte_osSemaphoreHandle handle, unsigned int *pTimeoutMsecs)
{
  unsigned int timeoutUsecs;
  unsigned int *pTimeoutUsecs;
  SceUInt result;
  pte_osResult osResult;

  if (pTimeoutMsecs == NULL)
    {
      pTimeoutUsecs = NULL;
    }
  else
    {
      timeoutUsecs = *pTimeoutMsecs * 1000;
      pTimeoutUsecs = &timeoutUsecs;
    }

  result = sceKernelWaitSema(handle, 1, pTimeoutUsecs);

  if (result == SCE_KERNEL_ERROR_OK)
    {
      osResult = PTE_OS_OK;
    }
  else if (result == SCE_KERNEL_ERROR_WAIT_TIMEOUT)
    {
      osResult = PTE_OS_TIMEOUT;
    }
  else
    {
      osResult = PTE_OS_GENERAL_FAILURE;
    }

  return osResult;
}


/*
 * Pend on a semaphore- and allow the pend to be cancelled.
 *
 * PSP OS provides no functionality to asynchronously interrupt a blocked call.  We simulte
 * this by polling on the main semaphore and the cancellation semaphore and sleeping in a loop.
 */
pte_osResult pte_osSemaphoreCancellablePend(pte_osSemaphoreHandle semHandle, unsigned int *pTimeout)
{
  pspThreadData *pThreadData;

  pThreadData = getThreadData(sceKernelGetThreadId());

  clock_t start_time;
  pte_osResult result =  PTE_OS_OK;
  unsigned int timeout;
  unsigned char timeoutEnabled;

  start_time = clock();

  // clock() is in microseconds, timeout as passed in was in milliseconds
  if (pTimeout == NULL)
    {
      timeout = 0;
      timeoutEnabled = 0;
    }
  else
    {
      timeout = *pTimeout * 1000;
      timeoutEnabled = 1;
    }

  while (1)
    {
      SceUInt semTimeout;
      int status;

      /* Poll semaphore */
      semTimeout = 0;
      status = sceKernelWaitSema(semHandle, 1, &semTimeout);

      if (status == SCE_KERNEL_ERROR_OK)
        {
          /* User semaphore posted to */
          result = PTE_OS_OK;
          break;
        }
      else if ((timeoutEnabled) && ((clock() - start_time) > timeout))
        {
          /* Timeout expired */
          result = PTE_OS_TIMEOUT;
          break;
        }
      else
        {
          SceKernelSemaInfo semInfo;

          if (pThreadData != NULL)
            {
	      SceUID osResult;
	      
              osResult = sceKernelReferSemaStatus(pThreadData->cancelSem, &semInfo);
	      
	      if (osResult == SCE_KERNEL_ERROR_OK)
		{
		  if (semInfo.currentCount > 0)
		    {
		      result = PTE_OS_INTERRUPTED;
		      break;
		    }
		  else
		    {
		      /* Nothing found and not timed out yet; let's yield so we're not
		       * in busy loop.
		       */
		      sceKernelDelayThread(POLLING_DELAY_IN_us);
		    }
		}
	      else
		{
		  result = PTE_OS_GENERAL_FAILURE;
		  break;
		}
            }
        }
    }

  return result;
}


/****************************************************************************
 *
 * Atomic Operations
 *
 ***************************************************************************/

int pte_osAtomicExchange(int *ptarg, int val)
{
  int intc = pspSdkDisableInterrupts();
  int origVal;

  origVal = *ptarg;

  *ptarg = val;

  pspSdkEnableInterrupts(intc);

  return origVal;

}

int pte_osAtomicCompareExchange(int *pdest, int exchange, int comp)
{
  int intc = pspSdkDisableInterrupts();
  int origVal;

  origVal = *pdest;

  if (*pdest == comp)
    {
      *pdest = exchange;
    }

  pspSdkEnableInterrupts(intc);

  return origVal;
}


int pte_osAtomicExchangeAdd(int volatile* pAddend, int value)
{
  int origVal;
  int intc = pspSdkDisableInterrupts();

  origVal = *pAddend;

  *pAddend += value;

  pspSdkEnableInterrupts(intc);

  return origVal;
}

int pte_osAtomicDecrement(int *pdest)
{
  int val;

  int intc = pspSdkDisableInterrupts();

  (*pdest)--;
  val = *pdest;

  pspSdkEnableInterrupts(intc);

  return val;
}

int pte_osAtomicIncrement(int *pdest)
{
  int val;

  int intc = pspSdkDisableInterrupts();

  (*pdest)++;
  val = *pdest;

  pspSdkEnableInterrupts(intc);

  return val;
}

/****************************************************************************
 *
 * Helper functions
 *
 ***************************************************************************/

static pspThreadData *getThreadData(SceUID threadHandle)
{
  pspThreadData *pThreadData;
  void *pTls;

  pTls = getTlsStructFromThread(threadHandle);

  pThreadData = (pspThreadData *) pteTlsGetValue(pTls, threadDataKey);

  return pThreadData;
}

static void *getTlsStructFromThread(SceUID thid)
{
  SceKernelThreadInfo thinfo;
  unsigned int ptr;
  unsigned int thrNum;
  void *pTls;
  int numMatches;


  thinfo.size = sizeof(SceKernelThreadInfo);

  sceKernelReferThreadStatus(thid, &thinfo);

  numMatches = sscanf(thinfo.name,"pthread%04d__%x", &thrNum, &ptr);

  /* If we were called from a pthread, use the TLS allocated when the thread
   * was created.  Otherwise, we were called from a non-pthread, so use the
   * "global".  This is a pretty bad hack, but necessary due to lack of TLS on PSP.
   */
  if (numMatches == 2)
    {
      pTls = (void *) ptr;
    }
  else
    {
      pTls = globalTls;
    }

  return pTls;
}

/****************************************************************************
 *
 * Thread Local Storage
 *
 ***************************************************************************/

pte_osResult pte_osTlsSetValue(unsigned int key, void * value)
{
  void *pTls;

  pTls = getTlsStructFromThread(sceKernelGetThreadId());

  return pteTlsSetValue(pTls, key, value);
}

void * pte_osTlsGetValue(unsigned int index)
{

  void *pTls;

  pTls = getTlsStructFromThread(sceKernelGetThreadId());

  return (void *) pteTlsGetValue(pTls, index);

}


pte_osResult pte_osTlsAlloc(unsigned int *pKey)
{
  void * pTls;

  pTls = getTlsStructFromThread(sceKernelGetThreadId());

  return pteTlsAlloc(pKey);

}

pte_osResult pte_osTlsFree(unsigned int index)
{
  return pteTlsFree(index);
}

/****************************************************************************
 *
 * Miscellaneous
 *
 ***************************************************************************/

int ftime(struct timeb *tb)
{
  struct timeval tv;
  struct timezone tz;

  gettimeofday(&tv, &tz);

  tb->time = tv.tv_sec;
  tb->millitm = tv.tv_usec / 1000;
  tb->timezone = tz.tz_minuteswest;
  tb->dstflag = tz.tz_dsttime;

  return 0;
}
\ No newline at end of file
diff --git a/platform/psp/pte-config.h b/platform/psp/pte-config.h
deleted file mode 100644
index 115c274dbb2411adfd4edc29825fc677af11eb15..0000000000000000000000000000000000000000
--- a/platform/psp/pte-config.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* config.h  */
-
-#ifndef PTE_CONFIG_H
-#define PTE_CONFIG_H
-
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/timeb.h>
-
-#define PTE_STATIC_LIB
-
-/*********************************************************************
- * Defaults: see target specific redefinitions below.
- *********************************************************************/
-
-/* We're building the pthreads-win32 library */
-#define PTE_BUILD
-
-typedef int pid_t;
-
-/* Define if you don't have Win32 errno. (eg. WinCE) */
-//#undef NEED_ERRNO
-
-/* Do we know about type mode_t? */
-//#undef HAVE_MODE_T
-
-//#undef HAVE_TIMEB
-//#define HAVE_TIMEB
-
-/* Define if you have the timespec struct */
-//#undef HAVE_STRUCT_TIMESPEC
-//#define HAVE_STRUCT_TIMESPEC
-
-#endif
diff --git a/platform/psp/pte_types.h b/platform/psp/pte_types.h
new file mode 100644
index 0000000000000000000000000000000000000000..4fc2b422b8945dce6ed8a78ddf84254e4e6dc022
--- /dev/null
+++ b/platform/psp/pte_types.h
@@ -0,0 +1,12 @@
+/* pte_types.h  */
+
+#ifndef PTE_TYPES_H
+#define PTE_TYPES_H
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+
+typedef int pid_t;
+
+#endif /* PTE_TYPES_H */
diff --git a/pthread.h b/pthread.h
index 9a6e76b55fc28589f614c2ac9030e54bb3a96578..d593d2e3db743f2f3e74a578c7664c5f5bdd6fff 100644
--- a/pthread.h
+++ b/pthread.h
@@ -44,7 +44,7 @@
 #if !defined( PTHREAD_H )
 #define PTHREAD_H
 
-#include <pte-config.h>
+#include <pte_types.h>
 
 #include <sched.h>
 
@@ -984,9 +984,7 @@ enum
 #endif
 
 
-#ifndef PTE_BUILD
-
-#ifdef PTE_CLEANUP_CXX
+#ifdef PTE_CXX_EXCEPTIONS
 
     /*
      * Redefine the C++ catch keyword to ensure that applications
@@ -996,9 +994,7 @@ enum
         catch( pte_exception & ) { throw; } \
         catch( E )
 
-#endif /* PTE_CLEANUP_CXX */
-
-#endif /* ! PTE_BUILD */
+#endif /* ! PTE_CXX_EXCEPTIONS */
 
 #undef PTE_LEVEL
 #undef PTE_LEVEL_MAX
diff --git a/sched.h b/sched.h
index 40d42375093a68c5e56f767ecb4c2fa822286ac8..464d0395f904b485f64bf166a27a2c0153273639 100644
--- a/sched.h
+++ b/sched.h
@@ -51,7 +51,7 @@
 #ifndef _SCHED_H
 #define _SCHED_H
 
-#include <pte-config.h>
+#include <pte_types.h>
 
 #undef PTE_LEVEL