少年修仙传客户端基础资源
hch
2024-04-11 4c71d74b77c9eb62a0323698c9a0db3b641a917e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
#include "il2cpp-config.h"
 
#if !IL2CPP_THREADS_STD && IL2CPP_THREADS_PTHREAD && !IL2CPP_TINY_WITHOUT_DEBUGGER
 
#include <limits>
#include <unistd.h>
#include <map>
#include <pthread.h>
#include <errno.h>
#include <string.h>
 
#if IL2CPP_TARGET_LINUX
#include <sys/prctl.h>
#include <sys/resource.h>
#endif
 
#include "ThreadImpl.h"
#include "PosixHelpers.h"
#include "os/Mutex.h"
 
 
namespace il2cpp
{
namespace os
{
/// An Event that we never signal. This is used for sleeping threads in an alertable state. They
/// simply wait on this object with the sleep timer as the timeout. This way we don't need a separate
/// codepath for implementing sleep logic.
    static Event s_ThreadSleepObject;
 
 
#define ASSERT_CALLED_ON_CURRENT_THREAD \
    IL2CPP_ASSERT(pthread_equal (pthread_self (), m_Handle) && "Must be called on current thread!");
 
 
    ThreadImpl::ThreadImpl()
        : m_Handle(0)
        , m_StartFunc(NULL)
        , m_StartArg(NULL)
        , m_CurrentWaitObject(NULL)
        , m_StackSize(IL2CPP_DEFAULT_STACK_SIZE)
    {
        pthread_mutex_init(&m_PendingAPCsMutex, NULL);
    }
 
    ThreadImpl::~ThreadImpl()
    {
        pthread_mutex_destroy(&m_PendingAPCsMutex);
    }
 
    ErrorCode ThreadImpl::Run(Thread::StartFunc func, void* arg, int64_t affinityMask)
    {
        // Store state for run wrapper.
        m_StartFunc = func;
        m_StartArg = arg;
 
        // Initialize thread attributes.
        pthread_attr_t attr;
        int s = pthread_attr_init(&attr);
        if (s)
            return kErrorCodeGenFailure;
 
#if defined(IL2CPP_ENABLE_PLATFORM_THREAD_AFFINTY)
#if IL2CPP_THREAD_HAS_CPU_SET
        if (affinityMask != Thread::kThreadAffinityAll)
        {
            cpu_set_t cpuset;
            CPU_ZERO(&cpuset);
            for (int i = 0; i < 64; ++i)
            {
                if (affinityMask & (1 << i))
                    CPU_SET(i, &cpuset);
            }
 
            pthread_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset);
        }
        else
        {
            // set create default core affinity
            pthread_attr_setaffinity_np(&attr, 0, NULL);
        }
#else
        pthread_attr_setaffinity_np(&attr, 0, NULL);
#endif // IL2CPP_THREAD_HAS_CPU_SET
#endif // defined(IL2CPP_ENABLE_PLATFORM_THREAD_AFFINTY)
 
 
#if defined(IL2CPP_ENABLE_PLATFORM_THREAD_STACKSIZE)
        pthread_attr_setstacksize(&attr, m_StackSize);
#endif
 
 
        // Create thread.
        pthread_t threadId;
        s = pthread_create(&threadId, &attr, &ThreadStartWrapper, this);
        if (s)
            return kErrorCodeGenFailure;
 
        // Destroy thread attributes.
        s = pthread_attr_destroy(&attr);
        if (s)
            return kErrorCodeGenFailure;
 
        // We're up and running.
        m_Handle = threadId;
 
        return kErrorCodeSuccess;
    }
 
    void* ThreadImpl::ThreadStartWrapper(void* arg)
    {
        ThreadImpl* thread = reinterpret_cast<ThreadImpl*>(arg);
 
        // Also set handle here. No matter which thread proceeds first,
        // we need to make sure the handle is set.
        thread->m_Handle = pthread_self();
 
        // Detach this thread since we will manage calling Join at the VM level
        // if necessary. Detaching it also prevents use from running out of thread
        // handles for background threads that are never joined.
        int returnValue = pthread_detach(thread->m_Handle);
        IL2CPP_ASSERT(returnValue == 0);
        (void)returnValue;
 
        // Run user code.
        thread->m_StartFunc(thread->m_StartArg);
 
        return 0;
    }
 
    uint64_t ThreadImpl::Id()
    {
        return posix::PosixThreadIdToThreadId(m_Handle);
    }
 
    void ThreadImpl::SetName(const char* name)
    {
        // Can only be set on current thread on OSX and Linux.
        if (pthread_self() != m_Handle)
            return;
 
#if IL2CPP_TARGET_DARWIN
        pthread_setname_np(name);
#elif IL2CPP_TARGET_LINUX || IL2CPP_TARGET_LUMIN || IL2CPP_TARGET_ANDROID || IL2CPP_ENABLE_PLATFORM_THREAD_RENAME
        if (pthread_setname_np(m_Handle, name) == ERANGE)
        {
            char buf[16]; // TASK_COMM_LEN=16
            strncpy(buf, name, sizeof(buf));
            buf[sizeof(buf) - 1] = '\0';
            pthread_setname_np(m_Handle, buf);
        }
#endif
    }
 
    void ThreadImpl::SetStackSize(size_t newsize)
    {
        // if newsize is zero we use the per-platform default value for size of stack
        if (newsize == 0)
        {
            newsize = IL2CPP_DEFAULT_STACK_SIZE;
        }
 
        m_StackSize = newsize;
    }
 
    int ThreadImpl::GetMaxStackSize()
    {
#if IL2CPP_TARGET_DARWIN || IL2CPP_TARGET_LINUX
        struct rlimit lim;
 
        /* If getrlimit fails, we don't enforce any limits. */
        if (getrlimit(RLIMIT_STACK, &lim))
            return INT_MAX;
        /* rlim_t is an unsigned long long on 64bits OSX but we want an int response. */
        if (lim.rlim_max > (rlim_t)INT_MAX)
            return INT_MAX;
        return (int)lim.rlim_max;
#else
        return INT_MAX;
#endif
    }
 
    void ThreadImpl::SetPriority(ThreadPriority priority)
    {
        ////TODO
    }
 
    ThreadPriority ThreadImpl::GetPriority()
    {
        /// TODO
        return kThreadPriorityNormal;
    }
 
    void ThreadImpl::QueueUserAPC(Thread::APCFunc function, void* context)
    {
        IL2CPP_ASSERT(function != NULL);
 
        // Put on queue.
        {
            pthread_mutex_lock(&m_PendingAPCsMutex);
            m_PendingAPCs.push_back(APCRequest(function, context));
            pthread_mutex_unlock(&m_PendingAPCsMutex);
        }
 
        // Interrupt an ongoing wait.
        posix::AutoLockWaitObjectDeletion lock;
        posix::PosixWaitObject* waitObject = m_CurrentWaitObject;
        if (waitObject)
            waitObject->InterruptWait();
    }
 
    void ThreadImpl::CheckForUserAPCAndHandle()
    {
        ASSERT_CALLED_ON_CURRENT_THREAD;
        pthread_mutex_lock(&m_PendingAPCsMutex);
 
        while (!m_PendingAPCs.empty())
        {
            APCRequest apcRequest = m_PendingAPCs.front();
 
            // Remove from list. Do before calling the function to make sure the list
            // is up to date in case the function throws.
            m_PendingAPCs.erase(m_PendingAPCs.begin());
 
            // Release mutex while we call the function so that we don't deadlock
            // if the function starts waiting on a thread that tries queuing an APC
            // on us.
            pthread_mutex_unlock(&m_PendingAPCsMutex);
 
            // Call function.
            apcRequest.callback(apcRequest.context);
 
            // Re-acquire mutex.
            pthread_mutex_lock(&m_PendingAPCsMutex);
        }
 
        pthread_mutex_unlock(&m_PendingAPCsMutex);
    }
 
    void ThreadImpl::SetWaitObject(posix::PosixWaitObject* waitObject)
    {
        // Cannot set wait objects on threads other than the current thread.
        ASSERT_CALLED_ON_CURRENT_THREAD;
 
        // This is an unprotected write as write acccess is restricted to the
        // current thread.
        m_CurrentWaitObject = waitObject;
    }
 
    void ThreadImpl::Sleep(uint32_t milliseconds, bool interruptible)
    {
        s_ThreadSleepObject.Wait(milliseconds, interruptible);
    }
 
    uint64_t ThreadImpl::CurrentThreadId()
    {
        return posix::PosixThreadIdToThreadId(pthread_self());
    }
 
    ThreadImpl* ThreadImpl::GetCurrentThread()
    {
        return Thread::GetCurrentThread()->m_Thread;
    }
 
    ThreadImpl* ThreadImpl::CreateForCurrentThread()
    {
        ThreadImpl* thread = new ThreadImpl();
        thread->m_Handle = pthread_self();
        return thread;
    }
 
    bool ThreadImpl::YieldInternal()
    {
        return sched_yield() == 0;
    }
 
#if IL2CPP_HAS_NATIVE_THREAD_CLEANUP
 
    static pthread_key_t s_CleanupKey;
    static Thread::ThreadCleanupFunc s_CleanupFunc;
 
    static void CleanupThreadIfCanceled(void* arg)
    {
        Thread::ThreadCleanupFunc cleanupFunc = s_CleanupFunc;
        if (cleanupFunc)
            cleanupFunc(arg);
    }
 
    void ThreadImpl::SetNativeThreadCleanup(Thread::ThreadCleanupFunc cleanupFunction)
    {
        if (cleanupFunction)
        {
            IL2CPP_ASSERT(!s_CleanupFunc);
            s_CleanupFunc = cleanupFunction;
            int result = pthread_key_create(&s_CleanupKey, &CleanupThreadIfCanceled);
            IL2CPP_ASSERT(!result);
            NO_UNUSED_WARNING(result);
        }
        else
        {
            IL2CPP_ASSERT(s_CleanupFunc);
            int result = pthread_key_delete(s_CleanupKey);
            IL2CPP_ASSERT(!result);
            NO_UNUSED_WARNING(result);
            s_CleanupFunc = NULL;
        }
    }
 
    void ThreadImpl::RegisterCurrentThreadForCleanup(void* arg)
    {
        IL2CPP_ASSERT(s_CleanupFunc);
        pthread_setspecific(s_CleanupKey, arg);
    }
 
    void ThreadImpl::UnregisterCurrentThreadForCleanup()
    {
        IL2CPP_ASSERT(s_CleanupFunc);
        void* data = pthread_getspecific(s_CleanupKey);
        if (data != NULL)
            pthread_setspecific(s_CleanupKey, NULL);
    }
 
#endif
}
}
 
#endif