2 Copyright 2010-2011, The AROS Development Team. All rights reserved.
8 #include <proto/exec.h>
12 struct TaskLocalNode
* tl_Succ
;
13 struct Task
* tl_Task
;
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
);
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 */
54 if (tl
->tl_Task
== me
)
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
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
);
107 if (tl
->tl_Task
== me
)
118 VOID
DestroyTLS(struct TaskLocalStorage
* tls
)
120 /* Destroy needs no lock. If a task is still iterating over list, we are doomed
122 struct TaskLocalNode
* tl
= tls
->tls_Head
, * temp
;