18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2008 Apple Inc. All rights reserved.
3635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * Copyright (C) 2009 Jian Li <jianli@chromium.org>
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met:
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1.  Redistributions of source code must retain the above copyright
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     notice, this list of conditions and the following disclaimer.
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2.  Redistributions in binary form must reproduce the above copyright
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     notice, this list of conditions and the following disclaimer in the
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     documentation and/or other materials provided with the distribution.
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     its contributors may be used to endorse or promote products derived
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     from this software without specific prior written permission.
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
30635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project/* Thread local storage is implemented by using either pthread API or Windows
31635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * native API. There is subtle semantic discrepancy for the cleanup function
32635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * implementation as noted below:
33635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *   @ In pthread implementation, the destructor function will be called
34635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *     repeatedly if there is still non-NULL value associated with the function.
35635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *   @ In Windows native implementation, the destructor function will be called
36635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *     only once.
37635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * This semantic discrepancy does not impose any problem because nowhere in
38635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * WebKit the repeated call bahavior is utilized.
39635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project */
40635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#ifndef WTF_ThreadSpecific_h
428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#define WTF_ThreadSpecific_h
438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <wtf/Noncopyable.h>
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
46635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#if USE(PTHREADS)
478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <pthread.h>
485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#elif PLATFORM(QT)
495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include <QThreadStorage>
5006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen#elif PLATFORM(GTK)
5106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen#include <glib.h>
52d0825bca7fe65beaee391d30da42e937db621564Steve Block#elif OS(WINDOWS)
53635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <windows.h>
548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#endif
558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WTF {
578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen#if !USE(PTHREADS) && !PLATFORM(QT) && !PLATFORM(GTK) && OS(WINDOWS)
59635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// ThreadSpecificThreadExit should be called each time when a thread is detached.
60635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// This is done automatically for threads created with WTF::createThread.
61635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid ThreadSpecificThreadExit();
62635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#endif
63635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
64ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdochtemplate<typename T> class ThreadSpecific {
65ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    WTF_MAKE_NONCOPYABLE(ThreadSpecific);
668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectpublic:
678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ThreadSpecific();
688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    T* operator->();
698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    operator T*();
708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    T& operator*();
718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectprivate:
7306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen#if !USE(PTHREADS) && !PLATFORM(QT) && !PLATFORM(GTK) && OS(WINDOWS)
74635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    friend void ThreadSpecificThreadExit();
75635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#endif
765ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen
775ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen    // Not implemented. It's technically possible to destroy a thread specific key, but one would need
785ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen    // to make sure that all values have been destroyed already (usually, that all threads that used it
795ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen    // have exited). It's unlikely that any user of this call will be in that situation - and having
805ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen    // a destructor defined can be confusing, given that it has such strong pre-requisites to work correctly.
815ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen    ~ThreadSpecific();
82635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    T* get();
848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    void set(T*);
858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    void static destroy(void* ptr);
868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen#if USE(PTHREADS) || PLATFORM(QT) || PLATFORM(GTK) || OS(WINDOWS)
88ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    struct Data {
89ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        WTF_MAKE_NONCOPYABLE(Data);
90ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    public:
918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        Data(T* value, ThreadSpecific<T>* owner) : value(value), owner(owner) {}
92231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#if PLATFORM(QT)
93231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        ~Data() { owner->destroy(this); }
94231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#endif
958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        T* value;
978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ThreadSpecific<T>* owner;
9806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen#if !USE(PTHREADS) && !PLATFORM(QT) && !PLATFORM(GTK)
99635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        void (*destructor)(void*);
100635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#endif
1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    };
102635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#endif
1038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
104d0825bca7fe65beaee391d30da42e937db621564Steve Block#if ENABLE(SINGLE_THREADED)
105d0825bca7fe65beaee391d30da42e937db621564Steve Block    T* m_value;
106d0825bca7fe65beaee391d30da42e937db621564Steve Block#else
107635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#if USE(PTHREADS)
1088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    pthread_key_t m_key;
1095f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#elif PLATFORM(QT)
1105f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    QThreadStorage<Data*> m_key;
11106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen#elif PLATFORM(GTK)
11206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    GStaticPrivate m_key;
113d0825bca7fe65beaee391d30da42e937db621564Steve Block#elif OS(WINDOWS)
114635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    int m_index;
1158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#endif
116d0825bca7fe65beaee391d30da42e937db621564Steve Block#endif
1178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project};
1188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
119d0825bca7fe65beaee391d30da42e937db621564Steve Block#if ENABLE(SINGLE_THREADED)
120d0825bca7fe65beaee391d30da42e937db621564Steve Blocktemplate<typename T>
121d0825bca7fe65beaee391d30da42e937db621564Steve Blockinline ThreadSpecific<T>::ThreadSpecific()
122d0825bca7fe65beaee391d30da42e937db621564Steve Block    : m_value(0)
123d0825bca7fe65beaee391d30da42e937db621564Steve Block{
124d0825bca7fe65beaee391d30da42e937db621564Steve Block}
125d0825bca7fe65beaee391d30da42e937db621564Steve Block
126d0825bca7fe65beaee391d30da42e937db621564Steve Blocktemplate<typename T>
127d0825bca7fe65beaee391d30da42e937db621564Steve Blockinline T* ThreadSpecific<T>::get()
128d0825bca7fe65beaee391d30da42e937db621564Steve Block{
129d0825bca7fe65beaee391d30da42e937db621564Steve Block    return m_value;
130d0825bca7fe65beaee391d30da42e937db621564Steve Block}
131d0825bca7fe65beaee391d30da42e937db621564Steve Block
132d0825bca7fe65beaee391d30da42e937db621564Steve Blocktemplate<typename T>
133d0825bca7fe65beaee391d30da42e937db621564Steve Blockinline void ThreadSpecific<T>::set(T* ptr)
134d0825bca7fe65beaee391d30da42e937db621564Steve Block{
135d0825bca7fe65beaee391d30da42e937db621564Steve Block    ASSERT(!get());
136d0825bca7fe65beaee391d30da42e937db621564Steve Block    m_value = ptr;
137d0825bca7fe65beaee391d30da42e937db621564Steve Block}
138d0825bca7fe65beaee391d30da42e937db621564Steve Block#else
139635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#if USE(PTHREADS)
1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projecttemplate<typename T>
1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectinline ThreadSpecific<T>::ThreadSpecific()
1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int error = pthread_key_create(&m_key, destroy);
1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (error)
1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CRASH();
1468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projecttemplate<typename T>
1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectinline T* ThreadSpecific<T>::get()
1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Data* data = static_cast<Data*>(pthread_getspecific(m_key));
1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return data ? data->value : 0;
1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projecttemplate<typename T>
1568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectinline void ThreadSpecific<T>::set(T* ptr)
1578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(!get());
1598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    pthread_setspecific(m_key, new Data(ptr, this));
1608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#elif PLATFORM(QT)
1635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qiantemplate<typename T>
1655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianinline ThreadSpecific<T>::ThreadSpecific()
1665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
1675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
1685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qiantemplate<typename T>
1705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianinline T* ThreadSpecific<T>::get()
1715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
1725f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    Data* data = static_cast<Data*>(m_key.localData());
1735f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return data ? data->value : 0;
1745f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
1755f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1765f1ab04193ad0130ca8204aadaceae083aca9881Feng Qiantemplate<typename T>
1775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianinline void ThreadSpecific<T>::set(T* ptr)
1785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
1795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    ASSERT(!get());
1805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    Data* data = new Data(ptr, this);
1815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    m_key.setLocalData(data);
1825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
1835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
18406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen#elif PLATFORM(GTK)
18506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen
18606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsentemplate<typename T>
18706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monseninline ThreadSpecific<T>::ThreadSpecific()
18806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen{
18906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    g_static_private_init(&m_key);
19006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen}
19106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen
19206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsentemplate<typename T>
19306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monseninline T* ThreadSpecific<T>::get()
19406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen{
19506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    Data* data = static_cast<Data*>(g_static_private_get(&m_key));
19606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    return data ? data->value : 0;
19706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen}
19806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen
19906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsentemplate<typename T>
20006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monseninline void ThreadSpecific<T>::set(T* ptr)
20106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen{
20206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    ASSERT(!get());
20306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    Data* data = new Data(ptr, this);
20406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    g_static_private_set(&m_key, data, destroy);
20506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen}
20606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen
207d0825bca7fe65beaee391d30da42e937db621564Steve Block#elif OS(WINDOWS)
208d0825bca7fe65beaee391d30da42e937db621564Steve Block
209d0825bca7fe65beaee391d30da42e937db621564Steve Block// TLS_OUT_OF_INDEXES is not defined on WinCE.
210d0825bca7fe65beaee391d30da42e937db621564Steve Block#ifndef TLS_OUT_OF_INDEXES
211d0825bca7fe65beaee391d30da42e937db621564Steve Block#define TLS_OUT_OF_INDEXES 0xffffffff
212d0825bca7fe65beaee391d30da42e937db621564Steve Block#endif
213635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
214635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// The maximum number of TLS keys that can be created. For simplification, we assume that:
215635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// 1) Once the instance of ThreadSpecific<> is created, it will not be destructed until the program dies.
216635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// 2) We do not need to hold many instances of ThreadSpecific<> data. This fixed number should be far enough.
217635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectconst int kMaxTlsKeySize = 256;
218635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
2198f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qianlong& tlsKeyCount();
2208f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng QianDWORD* tlsKeys();
221635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
222635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projecttemplate<typename T>
223635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectinline ThreadSpecific<T>::ThreadSpecific()
224635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    : m_index(-1)
225635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
226d0825bca7fe65beaee391d30da42e937db621564Steve Block    DWORD tlsKey = TlsAlloc();
227d0825bca7fe65beaee391d30da42e937db621564Steve Block    if (tlsKey == TLS_OUT_OF_INDEXES)
228635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        CRASH();
229635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
2308f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    m_index = InterlockedIncrement(&tlsKeyCount()) - 1;
231635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_index >= kMaxTlsKeySize)
232635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        CRASH();
233d0825bca7fe65beaee391d30da42e937db621564Steve Block    tlsKeys()[m_index] = tlsKey;
234635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
235635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
236635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projecttemplate<typename T>
237635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectinline ThreadSpecific<T>::~ThreadSpecific()
238635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
239635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Does not invoke destructor functions. They will be called from ThreadSpecificThreadExit when the thread is detached.
2408f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    TlsFree(tlsKeys()[m_index]);
241635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
242635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
243635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projecttemplate<typename T>
244635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectinline T* ThreadSpecific<T>::get()
245635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
2468f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    Data* data = static_cast<Data*>(TlsGetValue(tlsKeys()[m_index]));
247635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return data ? data->value : 0;
248635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
249635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
250635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projecttemplate<typename T>
251635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectinline void ThreadSpecific<T>::set(T* ptr)
252635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
253635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(!get());
254635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    Data* data = new Data(ptr, this);
255635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    data->destructor = &ThreadSpecific<T>::destroy;
2568f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    TlsSetValue(tlsKeys()[m_index], data);
257635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
258635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
259635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#else
260635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#error ThreadSpecific is not implemented for this platform.
261635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#endif
262d0825bca7fe65beaee391d30da42e937db621564Steve Block#endif
263635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
2648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projecttemplate<typename T>
2658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectinline void ThreadSpecific<T>::destroy(void* ptr)
2668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
267d0825bca7fe65beaee391d30da42e937db621564Steve Block#if !ENABLE(SINGLE_THREADED)
2688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Data* data = static_cast<Data*>(ptr);
2698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
270635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#if USE(PTHREADS)
271635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // We want get() to keep working while data destructor works, because it can be called indirectly by the destructor.
272635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Some pthreads implementations zero out the pointer before calling destroy(), so we temporarily reset it.
273635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    pthread_setspecific(data->owner->m_key, ptr);
27406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen#elif PLATFORM(GTK)
27506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    // See comment as above
27606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    g_static_private_set(&data->owner->m_key, data, 0);
277635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#endif
278231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#if PLATFORM(QT)
279231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // See comment as above
280231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    data->owner->m_key.setLocalData(data);
281231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#endif
282231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
283635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    data->value->~T();
284635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    fastFree(data->value);
285635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
286635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#if USE(PTHREADS)
287635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    pthread_setspecific(data->owner->m_key, 0);
2885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#elif PLATFORM(QT)
289231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Do nothing here
29006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen#elif PLATFORM(GTK)
29106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    g_static_private_set(&data->owner->m_key, 0, 0);
292d0825bca7fe65beaee391d30da42e937db621564Steve Block#elif OS(WINDOWS)
2938f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    TlsSetValue(tlsKeys()[data->owner->m_index], 0);
2948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#else
2958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#error ThreadSpecific is not implemented for this platform.
2968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#endif
2978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
298231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#if !PLATFORM(QT)
299635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    delete data;
300231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#endif
301d0825bca7fe65beaee391d30da42e937db621564Steve Block#endif
302635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
303635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
3048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projecttemplate<typename T>
3058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectinline ThreadSpecific<T>::operator T*()
3068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    T* ptr = static_cast<T*>(get());
3088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!ptr) {
309635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Set up thread-specific value's memory pointer before invoking constructor, in case any function it calls
310635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // needs to access the value, to avoid recursion.
31106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        ptr = static_cast<T*>(fastZeroedMalloc(sizeof(T)));
3128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        set(ptr);
313635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        new (ptr) T;
3148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return ptr;
3168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projecttemplate<typename T>
3198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectinline T* ThreadSpecific<T>::operator->()
3208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return operator T*();
3228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projecttemplate<typename T>
3258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectinline T& ThreadSpecific<T>::operator*()
3268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return *operator T*();
3288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#endif
333