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 +“environment” 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). It is intended to be +used to provide a pthreads API for 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 – 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 “typical” 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 – 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 – 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 “cancellable” +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 – 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 – 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 – 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> +– default priority for a created thread.</p> +<p align="left"><font face="Courier New, monospace">OS_MIN_PRIO</font> +– minimum thread priority.</p> +<p align="left"><font face="Courier New, monospace">OS_MAX_PRIO</font> +– maximum thread priority.</p> +<p align="left"><font face="Courier New, monospace">OS_MAX_SIMUL_THREADS</font> +– 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 “mutex04” 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 +“pthread10_80001234”, 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 “global” +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