revert between 56095 -> 55830 in arch
[AROS.git] / workbench / libs / mesa / src / aros / tls.c
blob69b3567b8fb37713e1eb5518e313f54ef3852497
1 /*
2 Copyright 2010-2011, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include "tls.h"
8 #include <proto/exec.h>
10 struct TaskLocalNode
12 struct TaskLocalNode * tl_Succ;
13 struct Task * tl_Task;
14 APTR tl_Data;
17 struct TaskLocalStorage
19 struct TaskLocalNode * tls_Head;
20 struct SignalSemaphore tls_WriteSemaphore;
23 /* Implementation uses locking only when adding objects. Objects are always added
24 at head. The list is never reordered, thus reading can be done without locking */
26 /* This approach is used to achieve acceptable performance. With semaphore-locking
27 of read path, the performance was degraded several times. The TLS is used to
28 hold current per-task GL context - retrieving this context MUST BE fast */
30 struct TaskLocalStorage * CreateTLS()
32 struct TaskLocalStorage * tls =
33 AllocVec(sizeof(struct TaskLocalStorage), MEMF_PUBLIC | MEMF_CLEAR);
35 InitSemaphore(&tls->tls_WriteSemaphore);
36 tls->tls_Head = NULL;
38 return tls;
41 VOID InsertIntoTLS(struct TaskLocalStorage * tls, APTR ptr)
43 struct TaskLocalNode * tl = tl = tls->tls_Head;
44 struct Task * me = FindTask(NULL);
45 struct TaskLocalNode * selected = NULL;
47 /* Assumption: one task cannot be reviewing the list and adding the head
48 "at the same time" - do not alter this function to recurse */
49 /* Assumption: only task A can add entry for task A */
51 /* Check if task's storage is already on the list */
52 while(tl)
54 if (tl->tl_Task == me)
56 selected = tl;
57 break;
59 tl = tl->tl_Succ;
62 if (!selected)
64 /* No, it is not. Create, set task pointer and at to head of list */
65 selected = AllocVec(sizeof(struct TaskLocalNode), MEMF_PUBLIC | MEMF_CLEAR);
66 selected->tl_Task = me;
67 ObtainSemaphore(&tls->tls_WriteSemaphore);
68 selected->tl_Succ = tls->tls_Head;
69 tls->tls_Head = selected;
70 ReleaseSemaphore(&tls->tls_WriteSemaphore);
74 /* Set the passed value */
75 selected->tl_Data = ptr;
78 VOID ClearFromTLS(struct TaskLocalStorage * tls)
80 /* Clearing is inserting a NULL. Element can't be removed from list - since
81 there is no read locking, altering structure of list when other tasks
82 are reading it, would cause crashes */
83 /* TODO: How real clearing can be achieved:
84 * a) acquire write lock
85 * b) copy all element (copy not relink!) from _current list to _new list except for the element that
86 * is beeing cleared
87 * c) _old = _current, _current = _new
88 * d) release write lock
90 * How to delete _old? It can't be deleted right away, because some read tasks can be iterating over it.
91 * a) put it on garbage collect list (the whole list, not relinking nodes!) and clear it when shutting down
92 * b) use memory pool to allocate all TLS objects and clear pool at shutdown
94 * Solution b is much easier and convenient
96 InsertIntoTLS(tls, NULL);
99 APTR GetFromTLS(struct TaskLocalStorage * tls)
101 struct TaskLocalNode * tl = tls->tls_Head;
102 struct Task * me = FindTask(NULL);
103 APTR data = NULL;
105 while(tl)
107 if (tl->tl_Task == me)
109 data = tl->tl_Data;
110 break;
112 tl = tl->tl_Succ;
115 return data;
118 VOID DestroyTLS(struct TaskLocalStorage * tls)
120 /* Destroy needs no lock. If a task is still iterating over list, we are doomed
121 anyway */
122 struct TaskLocalNode * tl = tls->tls_Head, * temp;
124 while (tl)
126 temp = tl->tl_Succ;
127 FreeVec(tl);
128 tl = temp;
131 FreeVec(tls);