xref: /relibc/pthreads-emb/platform/dspbios/dspbios-osal.c (revision 062c5bc4dfeed2c1bed58ed4810dd27adb32c68d)
1 /*
2  * psp_osal.h
3  *
4  * Description:
5  *
6  * --------------------------------------------------------------------------
7  *
8  *      Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
9  *      Copyright(C) 2008 Jason Schmidlapp
10  *
11  *      Contact Email: jschmidlapp@users.sourceforge.net
12  *
13  *      This library is free software; you can redistribute it and/or
14  *      modify it under the terms of the GNU Lesser General Public
15  *      License as published by the Free Software Foundation; either
16  *      version 2 of the License, or (at your option) any later version.
17  *
18  *      This library is distributed in the hope that it will be useful,
19  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  *      Lesser General Public License for more details.
22  *
23  *      You should have received a copy of the GNU Lesser General Public
24  *      License along with this library in the file COPYING.LIB;
25  *      if not, write to the Free Software Foundation, Inc.,
26  *      59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
27  */
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 
32 #include <std.h>
33 #include <clk.h>
34 #include <lck.h>
35 #include <mbx.h>
36 
37 #include <pthread.h>
38 
39 #include "tls-helper.h"
40 #include "pte_osal.h"
41 
42 #define POLLING_DELAY_IN_ticks 10
43 
44 #define DSPBIOS_MAX_TLS 32
45 
46 #define DEFAULT_STACK_SIZE_BYTES 4096
47 
48 /*
49  * Data stored on a per-thread basis - allocated in pte_osThreadCreate
50  * and freed in pte_osThreadDelete.
51  */
52 typedef struct dspbiosThreadData
53   {
54     /* Semaphore used to wait for threads to end.  Posted to in pte_osThreadExit() */
55     SEM_Handle joinSem;
56 
57     /* Semaphore used for cancellation.  Posted to by pte_osThreadCancel, polled in pte_osSemaphoreCancellablePend */
58     SEM_Handle cancelSem;
59 
60     /* Initial priority of the thread. */
61     int priority;
62 
63   } dspbiosThreadData;
64 
65 
66 /* Task and mailbox used for cleaning up detached threads */
67 static TSK_Handle gcTaskHandle;
68 static MBX_Handle gcMailbox;
69 
70 /* TLS key used to access dspbiosThreadData struct for reach thread. */
71 static unsigned int threadDataKey;
72 
73 
74 /*
75  *
76  * Helper functions
77  *
78  */
79 
80 /* Returns a pointer to the per thread control info */
getThreadData(TSK_Handle threadHandle)81 static dspbiosThreadData * getThreadData(TSK_Handle threadHandle)
82 {
83 
84   dspbiosThreadData *pThreadData;
85   void * pTls;
86 
87   pTls = (void *) TSK_getenv(threadHandle);
88 
89   pThreadData = (dspbiosThreadData *) pteTlsGetValue(pTls, threadDataKey);
90 
91   return pThreadData;
92 }
93 
94 /* Converts milliseconds to system ticks (for TSK_sleep, SEM_pend, etc) */
msecsToSysTicks(int msecs)95 static int msecsToSysTicks(int msecs)
96 {
97   int ticks = CLK_countspms() / CLK_getprd() * msecs;
98 
99   ticks = ticks / 100; // sim only
100 
101   return ticks;
102 }
103 
104 /* Garbage collector thread to free resources from detached threads */
dspbiosGarbageCollectorMain()105 void dspbiosGarbageCollectorMain()
106 {
107 
108   gcMailbox = MBX_create(sizeof(void*), 10, NULL);
109 
110   while (1)
111     {
112       Bool status;
113       void * pTask;
114 
115       /* Wait for dying threads to post their handles to our mailbox */
116       status = MBX_pend(gcMailbox, &pTask, SYS_FOREVER);
117 
118       if (status)
119         {
120           TSK_delete((TSK_Handle) pTask);
121         }
122     }
123 
124   /* Never returns */
125 }
126 
127 /****************************************************************************
128  *
129  * Initialization
130  *
131  ***************************************************************************/
132 
133 /*
134  * Initializes the OSAL.
135  *
136  *   1. Initialize TLS support.
137  *   2. Allocate control data TLS key.
138  *   3. Start garbage collector thread.
139  */
pte_osInit(void)140 pte_osResult pte_osInit(void)
141 {
142   pte_osResult result;
143   TSK_Attrs attrs;
144 
145   /* Allocate and initialize TLS support */
146   result = pteTlsGlobalInit(DSPBIOS_MAX_TLS);
147 
148   if (result == PTE_OS_OK)
149     {
150       /* Allocate a key that we use to store control information (e.g. cancellation semaphore) per thread */
151       result = pteTlsAlloc(&threadDataKey);
152 
153       if (result == PTE_OS_OK)
154 	{
155 	  /* Create a low priority task to free resources for detached threads */
156 	  attrs = TSK_ATTRS;
157 	  attrs.priority = 1; /* just above idle task */
158 	  attrs.name = "pthread-gc";
159 
160 	  gcTaskHandle = TSK_create((Fxn) dspbiosGarbageCollectorMain, &attrs);
161 
162 	  /* Give the garbage collector task a chance to run and create the mailbox */
163 	  TSK_sleep(1);
164 
165 	  if (gcTaskHandle == NULL)
166 	    {
167 	      result = PTE_OS_NO_RESOURCES;
168 	    }
169 	}
170     }
171 
172   return result;
173 }
174 
175 /****************************************************************************
176  *
177  * Threads
178  *
179  ***************************************************************************/
180 
181 
182 /* Entry point for new threads */
dspbiosStubThreadEntry(void * argv,pte_osThreadEntryPoint entryPoint)183 void dspbiosStubThreadEntry (void *argv, pte_osThreadEntryPoint entryPoint)
184 {
185   (*(entryPoint))(argv);
186   return;
187 }
188 
189 /*
190  * Creates a new thread, allocates resources, etc.
191  *
192  * The thread is created in a suspended state; execution will actually start
193  * when pte_osThreadStart() is called.  Setting the priority to a -1 will start the
194  * thread in a suspended state.  pte_osThreadStart then sets the real priority which
195  * will start the thread executing.
196  *
197  * In order for dynamic tasks to work, you must set up a heap for DSP/BIOS to allocate their
198  * stacks from.  This should be done in the projects tcf or cdb file.
199  *
200  */
pte_osThreadCreate(pte_osThreadEntryPoint entryPoint,int stackSize,int initialPriority,void * argv,pte_osThreadHandle * ppte_osThreadHandle)201 pte_osResult pte_osThreadCreate(pte_osThreadEntryPoint entryPoint,
202                                 int stackSize,
203                                 int initialPriority,
204                                 void *argv,
205                                 pte_osThreadHandle* ppte_osThreadHandle)
206 {
207   TSK_Handle handle;
208   TSK_Attrs attrs;
209   void *pTls;
210   pte_osResult result;
211   dspbiosThreadData *pThreadData;
212 
213   /* Make sure that the stack we're going to allocate is big enough */
214   if (stackSize < DEFAULT_STACK_SIZE_BYTES)
215     {
216       stackSize = DEFAULT_STACK_SIZE_BYTES;
217     }
218 
219   /* Allocate TLS structure for this thread. */
220   pTls = pteTlsThreadInit();
221   if (pTls == NULL)
222     {
223       result = PTE_OS_NO_RESOURCES;
224       goto FAIL0;
225     }
226 
227 
228   /* Allocate some memory for our per-thread control data.  We use this for:
229    *   1. join semaphore (used to wait for thread termination)
230    *   2. cancellation semaphore (used to signal a thread to cancel)
231    *   3. initial priority (used in stub entry point)
232    */
233   pThreadData = (dspbiosThreadData*) malloc(sizeof(dspbiosThreadData));
234 
235   if (pThreadData == NULL)
236     {
237       pteTlsThreadDestroy(pTls);
238 
239       result = PTE_OS_NO_RESOURCES;
240       goto FAIL0;
241     }
242 
243   /* Save a pointer to our per-thread control data as a TLS value */
244   pteTlsSetValue(pTls, threadDataKey, pThreadData);
245 
246   /* Create semaphores and save handles */
247   pThreadData->joinSem = SEM_create(0, NULL);
248   pThreadData->cancelSem = SEM_create(0, NULL);
249 
250   /* Save the initial priority - we need it when we
251    * actually start the thread */
252   pThreadData->priority = initialPriority;
253 
254   /*
255    * Fill out parameters for TSK_create:
256    */
257   attrs = TSK_ATTRS;
258 
259   /* Use  value specified by user */
260   attrs.stacksize = stackSize;
261 
262   attrs.priority  = -1;
263 
264   /* Save our TLS structure as the task's environment. */
265   attrs.environ   = pTls;
266 
267   handle = TSK_create((Fxn) dspbiosStubThreadEntry, &attrs, argv, entryPoint);
268 
269   if (handle != NULL)
270     {
271       /* Everything worked, return handle to caller */
272       *ppte_osThreadHandle = handle;
273       result = PTE_OS_OK;
274     }
275   else
276     {
277       /* Something went wrong - assume that it was due to lack of resources. */
278       free(pThreadData);
279       pteTlsThreadDestroy(pTls);
280 
281       result = PTE_OS_NO_RESOURCES;
282     }
283 
284 FAIL0:
285   return result;
286 }
287 
288 /* Start executing a thread.
289  *
290  * Get the priority that the user specified when they called
291  * pte_osThreadCreate and set the priority of the thread.  This
292  * will start the thread executing.
293  */
pte_osThreadStart(pte_osThreadHandle osThreadHandle)294 pte_osResult pte_osThreadStart(pte_osThreadHandle osThreadHandle)
295 {
296 
297   dspbiosThreadData *pThreadData;
298 
299   pThreadData = getThreadData(osThreadHandle);
300 
301   TSK_setpri(osThreadHandle, pThreadData->priority);
302 
303   return PTE_OS_OK;
304 
305 }
306 
307 
308 /*
309  * Exit from a thread.
310  *
311  * Post to the join semaphore in case a pthread_join is
312  * waiting for us to exit.
313  */
pte_osThreadExit()314 void pte_osThreadExit()
315 {
316   TSK_Handle thisTask;
317   dspbiosThreadData *pThreadData;
318 
319   thisTask = TSK_self();
320 
321   pThreadData = getThreadData(thisTask);
322 
323   if (pThreadData != NULL)
324     {
325       SEM_post(pThreadData->joinSem);
326     }
327 
328   TSK_exit();
329 
330 }
331 
pte_osThreadExitAndDelete(pte_osThreadHandle handle)332 pte_osResult pte_osThreadExitAndDelete(pte_osThreadHandle handle)
333 {
334   dspbiosThreadData *pThreadData;
335   void * pTls;
336 
337   pThreadData = getThreadData(handle);
338 
339   pTls = (void *) TSK_getenv(handle);
340 
341   /* Free the per thread data (join & cancel semaphores, etc) */
342   SEM_delete(pThreadData->joinSem);
343   SEM_delete(pThreadData->cancelSem);
344 
345   free(pThreadData);
346 
347   /* Free the TLS data structure */
348   pteTlsThreadDestroy(pTls);
349 
350   /* Send thread handle to garbage collector task so it can free
351    * resources from a different context */
352   MBX_post(gcMailbox, &handle, SYS_FOREVER);
353 
354   TSK_exit();
355 
356   return PTE_OS_OK;
357 }
358 
359 /* Clean up a thread.
360  *
361  * If this is called from the thread itself, instead of actually freeing up
362  * resources, post the thread handle to a mailbox which will be picked
363  * up by the garbage collector thread.  Resources will be freed from there.
364  * This is necessary because DSP/BIOS does not free resources when a
365  * thread exits.
366  */
pte_osThreadDelete(pte_osThreadHandle handle)367 pte_osResult pte_osThreadDelete(pte_osThreadHandle handle)
368 {
369 
370   dspbiosThreadData *pThreadData;
371   void * pTls;
372 
373   pThreadData = getThreadData(handle);
374 
375   pTls = (void *) TSK_getenv(handle);
376 
377   /* Free the per thread data (join & cancel semaphores, etc) */
378   SEM_delete(pThreadData->joinSem);
379   SEM_delete(pThreadData->cancelSem);
380 
381   free(pThreadData);
382 
383   /* Free the TLS data structure */
384   pteTlsThreadDestroy(pTls);
385 
386   TSK_delete(handle);
387 
388   return PTE_OS_OK;
389 }
390 
391 /* Wait for a thread to exit.
392  *
393  * Since DSP/BIOS doesn't have a explicit system call for this, we
394  * emulate it using a semaphore that is posted to when the thread
395  * exits.
396  */
pte_osThreadWaitForEnd(pte_osThreadHandle threadHandle)397 pte_osResult pte_osThreadWaitForEnd(pte_osThreadHandle threadHandle)
398 {
399   TSK_Stat taskStats;
400   pte_osResult result;
401 
402   /* Prevent context switches to prevent the thread from
403    * changing states */
404   TSK_disable();
405 
406   /* First, check if the thread has already terminated. */
407   TSK_stat(threadHandle, &taskStats);
408 
409   if (taskStats.mode != TSK_TERMINATED)
410     {
411       dspbiosThreadData *pThreadData;
412       dspbiosThreadData *pSelfThreadData;
413 
414       pThreadData = getThreadData(threadHandle);
415       pSelfThreadData = getThreadData(TSK_self());
416 
417       TSK_enable();
418 
419       /* This needs to be cancellable, so poll instead of block,
420        * similar to what we do for pte_OsSemaphoreCancellablePend. */
421       while (1)
422 	{
423 	  if (SEM_count(pThreadData->joinSem) > 0)
424 	    {
425 	      /* The thread has exited. */
426 	      result = PTE_OS_OK;
427 	      break;
428 	    }
429 	  else if ((pSelfThreadData != NULL) && SEM_count(pSelfThreadData->cancelSem) > 0)
430 	    {
431 	      /* The thread was cancelled */
432 	      result = PTE_OS_INTERRUPTED;
433 	      break;
434 	    }
435           else
436             {
437               /* Nothing found and not timed out yet; let's yield so we're not
438                * in busy loop. */
439               TSK_sleep(POLLING_DELAY_IN_ticks);
440             }
441         }
442 
443     }
444   else
445     {
446       /* Thread is already terminated, just return OK */
447       TSK_enable();
448       result = PTE_OS_OK;
449     }
450 
451   return result;
452 }
453 
454 /* Cancels the specified thread.  This will 1) make pte_osSemaphoreCancellablePend return if it is currently
455  * blocked and will make pte_osThreadCheckCancel return TRUE.
456  *
457  * To accomplish this, we post to the cancellation semaphore for the specified thread.
458  */
pte_osThreadCancel(pte_osThreadHandle threadHandle)459 pte_osResult pte_osThreadCancel(pte_osThreadHandle threadHandle)
460 {
461   dspbiosThreadData *pThreadData;
462 
463   pThreadData = getThreadData(threadHandle);
464 
465   if (pThreadData != NULL)
466     {
467       SEM_post(pThreadData->cancelSem);
468     }
469 
470   return PTE_OS_OK;
471 }
472 
473 
474 /*
475  * Checks to see if pte_osThreadCancel has been called for the specified thread.  Just check the
476  * value of the cancellation semaphore associated with the thread.
477  */
pte_osThreadCheckCancel(pte_osThreadHandle threadHandle)478 pte_osResult pte_osThreadCheckCancel(pte_osThreadHandle threadHandle)
479 {
480 
481   dspbiosThreadData *pThreadData;
482 
483   pThreadData = getThreadData(threadHandle);
484 
485   if (pThreadData != NULL)
486     {
487       if (SEM_count(pThreadData->cancelSem) > 0)
488         {
489           return PTE_OS_INTERRUPTED;
490         }
491       else
492         {
493           return PTE_OS_OK;
494         }
495     }
496   else
497     {
498       /* We're being called from a pure OS thread which can't be cancelled. */
499       return PTE_OS_OK;
500     }
501 
502 
503 }
504 
pte_osThreadSleep(unsigned int msecs)505 void pte_osThreadSleep(unsigned int msecs)
506 {
507   int ticks = msecsToSysTicks(msecs);
508 
509   TSK_sleep(ticks);
510 }
511 
pte_osThreadGetHandle(void)512 pte_osThreadHandle pte_osThreadGetHandle(void)
513 {
514   return TSK_self();
515 }
516 
pte_osThreadGetPriority(pte_osThreadHandle threadHandle)517 int pte_osThreadGetPriority(pte_osThreadHandle threadHandle)
518 {
519   return TSK_getpri(threadHandle);
520 }
521 
pte_osThreadSetPriority(pte_osThreadHandle threadHandle,int newPriority)522 pte_osResult pte_osThreadSetPriority(pte_osThreadHandle threadHandle, int newPriority)
523 {
524   TSK_setpri(threadHandle, newPriority);
525 
526   return PTE_OS_OK;
527 }
528 
pte_osThreadGetMinPriority()529 int pte_osThreadGetMinPriority()
530 {
531   return TSK_MINPRI;
532 }
533 
pte_osThreadGetMaxPriority()534 int pte_osThreadGetMaxPriority()
535 {
536   return TSK_MAXPRI;
537 }
538 
pte_osThreadGetDefaultPriority()539 int pte_osThreadGetDefaultPriority()
540 {
541   /* Pick something in the middle */
542   return ((TSK_MINPRI + TSK_MAXPRI) / 2);
543 }
544 
545 /****************************************************************************
546  *
547  * Mutexes
548  *
549  ***************************************************************************/
550 
pte_osMutexCreate(pte_osMutexHandle * pHandle)551 pte_osResult pte_osMutexCreate(pte_osMutexHandle *pHandle)
552 {
553 
554   *pHandle = LCK_create(NULL);
555 
556   if (*pHandle == NULL)
557     {
558       return PTE_OS_NO_RESOURCES;
559     }
560   else
561     {
562       return PTE_OS_OK;
563     }
564 }
565 
pte_osMutexDelete(pte_osMutexHandle handle)566 pte_osResult pte_osMutexDelete(pte_osMutexHandle handle)
567 {
568   LCK_delete(handle);
569 
570   return PTE_OS_OK;
571 }
572 
pte_osMutexLock(pte_osMutexHandle handle)573 pte_osResult pte_osMutexLock(pte_osMutexHandle handle)
574 {
575   LCK_pend(handle, SYS_FOREVER);
576 
577   return PTE_OS_OK;
578 }
579 
pte_osMutexUnlock(pte_osMutexHandle handle)580 pte_osResult pte_osMutexUnlock(pte_osMutexHandle handle)
581 {
582 
583   LCK_post(handle);
584 
585   return PTE_OS_OK;
586 }
587 
588 /****************************************************************************
589  *
590  * Semaphores
591  *
592  ***************************************************************************/
593 
pte_osSemaphoreCreate(int initialValue,pte_osSemaphoreHandle * pHandle)594 pte_osResult pte_osSemaphoreCreate(int initialValue, pte_osSemaphoreHandle *pHandle)
595 {
596 
597   *pHandle = SEM_create(initialValue, NULL);
598 
599   if (*pHandle == NULL)
600     {
601       return PTE_OS_NO_RESOURCES;
602     }
603   else
604     {
605       return PTE_OS_OK;
606     }
607 
608 }
609 
pte_osSemaphoreDelete(pte_osSemaphoreHandle handle)610 pte_osResult pte_osSemaphoreDelete(pte_osSemaphoreHandle handle)
611 {
612   SEM_delete(handle);
613 
614   return PTE_OS_OK;
615 }
616 
617 
pte_osSemaphorePost(pte_osSemaphoreHandle handle,int count)618 pte_osResult pte_osSemaphorePost(pte_osSemaphoreHandle handle, int count)
619 {
620   int i;
621 
622   for (i=0;i<count;i++)
623     {
624       SEM_post(handle);
625     }
626 
627   return PTE_OS_OK;
628 }
629 
pte_osSemaphorePend(pte_osSemaphoreHandle handle,unsigned int * pTimeoutMsecs)630 pte_osResult pte_osSemaphorePend(pte_osSemaphoreHandle handle, unsigned int *pTimeoutMsecs)
631 {
632   Bool status;
633   unsigned int timeoutTicks;
634 
635   if (pTimeoutMsecs == NULL)
636     {
637       timeoutTicks = SYS_FOREVER;
638     }
639   else
640     {
641       timeoutTicks = msecsToSysTicks(*pTimeoutMsecs);
642     }
643 
644 
645   status = SEM_pend(handle, timeoutTicks);
646 
647   if (status)
648     {
649       return PTE_OS_OK;
650     }
651   else
652     {
653       return PTE_OS_TIMEOUT;
654     }
655 
656 }
657 
658 
659 
660 /*
661  * Pend on a semaphore- and allow the pend to be cancelled.
662  *
663  * DSP/BIOS provides no functionality to asynchronously interrupt a blocked call.  We simulte
664  * this by polling on the main semaphore and the cancellation semaphore and sleeping in a loop.
665  */
pte_osSemaphoreCancellablePend(pte_osSemaphoreHandle semHandle,unsigned int * pTimeout)666 pte_osResult pte_osSemaphoreCancellablePend(pte_osSemaphoreHandle semHandle, unsigned int *pTimeout)
667 {
668 
669 
670   clock_t start_time;
671   clock_t current_time;
672   pte_osResult result =  PTE_OS_OK;
673   int timeout;
674 
675   dspbiosThreadData *pThreadData;
676 
677   pThreadData = getThreadData(TSK_self());
678 
679 
680   start_time = CLK_getltime();
681 
682   if (pTimeout == NULL)
683     {
684       timeout = -1;
685     }
686   else
687     {
688       timeout = msecsToSysTicks(*pTimeout);
689     }
690 
691   while (1)
692     {
693       Bool semTimeout;
694       int status;
695 
696       /* Poll semaphore */
697       semTimeout = 0;
698 
699       current_time = CLK_getltime();
700 
701       status = SEM_pend(semHandle, semTimeout);
702 
703       if (status == TRUE)
704         {
705           /* The user semaphore was posted to */
706           result = PTE_OS_OK;
707           break;
708         }
709       else if ((timeout != -1) && ((current_time - start_time) > timeout))
710         {
711           /* The timeout expired */
712           result = PTE_OS_TIMEOUT;
713           break;
714         }
715       else
716         {
717           if ((pThreadData != NULL) && SEM_count(pThreadData->cancelSem) > 0)
718             {
719               /* The thread was cancelled */
720               result = PTE_OS_INTERRUPTED;
721               break;
722             }
723           else
724             {
725               /* Nothing found and not timed out yet; let's yield so we're not
726                * in busy loop. */
727               TSK_sleep(POLLING_DELAY_IN_ticks);
728             }
729         }
730 
731     }
732 
733   return result;
734 
735 }
736 
737 
738 /****************************************************************************
739  *
740  * Atomic Operations
741  *
742  ***************************************************************************/
pte_osAtomicExchange(int * ptarg,int val)743 int pte_osAtomicExchange(int *ptarg, int val)
744 {
745 
746   long origVal;
747   Uns oldCSR;
748 
749   oldCSR = HWI_disable();
750 
751   origVal = *ptarg;
752 
753   *ptarg = val;
754 
755   HWI_restore(oldCSR);
756 
757   return origVal;
758 
759 }
760 
pte_osAtomicCompareExchange(int * pdest,int exchange,int comp)761 int pte_osAtomicCompareExchange(int *pdest, int exchange, int comp)
762 {
763 
764   int origVal;
765   Uns oldCSR;
766 
767   oldCSR = HWI_disable();
768 
769 
770   origVal = *pdest;
771 
772   if (*pdest == comp)
773     {
774       *pdest = exchange;
775     }
776 
777   HWI_restore(oldCSR);
778 
779 
780   return origVal;
781 
782 }
783 
pte_osAtomicExchangeAddInt(int volatile * pAddend,int value)784 int pte_osAtomicExchangeAddInt(int volatile* pAddend, int value)
785 {
786 
787   int origVal;
788   Uns oldCSR;
789 
790   oldCSR = HWI_disable();
791 
792 
793   origVal = *pAddend;
794 
795   *pAddend += value;
796 
797   HWI_restore(oldCSR);
798 
799 
800   return origVal;
801 
802 }
803 
pte_osAtomicExchangeAdd(int volatile * pAddend,int value)804 int pte_osAtomicExchangeAdd(int volatile* pAddend, int value)
805 {
806 
807   int origVal;
808   Uns oldCSR;
809 
810   oldCSR = HWI_disable();
811 
812 
813   origVal = *pAddend;
814 
815   *pAddend += value;
816 
817   HWI_restore(oldCSR);
818 
819 
820   return origVal;
821 }
822 
pte_osAtomicDecrement(int * pdest)823 int pte_osAtomicDecrement(int *pdest)
824 {
825   int val;
826   Uns oldCSR;
827 
828   oldCSR = HWI_disable();
829 
830 
831   (*pdest)--;
832   val = *pdest;
833 
834   HWI_restore(oldCSR);
835 
836   return val;
837 
838 }
839 
pte_osAtomicIncrement(int * pdest)840 int pte_osAtomicIncrement(int *pdest)
841 {
842   int val;
843   Uns oldCSR;
844 
845   oldCSR = HWI_disable();
846 
847   (*pdest)++;
848 
849   val = *pdest;
850 
851   HWI_restore(oldCSR);
852 
853 
854   return val;
855 }
856 
857 /****************************************************************************
858  *
859  * Thread Local Storage
860  *
861  ***************************************************************************/
862 
pte_osTlsSetValue(unsigned int index,void * value)863 pte_osResult pte_osTlsSetValue(unsigned int index, void * value)
864 {
865   void *pTls;
866 
867   pTls = (void *) TSK_getenv(TSK_self());
868 
869   if (pTls == NULL)
870     {
871       // Apparently no TLS structure has been allocated for this thread
872       // Probably because this is a native OS thread
873       pTls = pteTlsThreadInit();
874 
875 
876       TSK_setenv(TSK_self(), pTls);
877     }
878 
879   return pteTlsSetValue(pTls, index, value);
880 }
881 
882 
883 
pte_osTlsGetValue(unsigned int index)884 void * pte_osTlsGetValue(unsigned int index)
885 {
886   void *pTls;
887 
888   pTls = (void *) TSK_getenv(TSK_self());
889 
890   return (void *) pteTlsGetValue(pTls, index);
891 
892 }
893 
894 
895 // Note that key value must be > 0
pte_osTlsAlloc(unsigned int * pKey)896 pte_osResult pte_osTlsAlloc(unsigned int *pKey)
897 {
898   return pteTlsAlloc(pKey);
899 }
900 
901 
pte_osTlsFree(unsigned int index)902 pte_osResult pte_osTlsFree(unsigned int index)
903 {
904   return pteTlsFree(index);
905 
906 }
907 
908 
ftime(struct timeb * tp)909 int ftime(struct timeb *tp)
910 {
911   int ltime = (CLK_getltime() * CLK_cpuCyclesPerLtime()) / CLK_cpuCyclesPerLtime();
912   int secs = ltime / 1000;
913   int msecs = ltime % 1000;
914 
915   tp->dstflag = 0;
916   tp->timezone = 0;
917   tp->time = secs;
918   tp->millitm = msecs;
919 
920   return 0;
921 }
922 
923 
924