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