thread.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979
  1. /**
  2. * WinPR: Windows Portable Runtime
  3. * Process Thread Functions
  4. *
  5. * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
  6. * Copyright 2015 Hewlett-Packard Development Company, L.P.
  7. *
  8. * Licensed under the Apache License, Version 2.0 (the "License");
  9. * you may not use this file except in compliance with the License.
  10. * You may obtain a copy of the License at
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  14. * Unless required by applicable law or agreed to in writing, software
  15. * distributed under the License is distributed on an "AS IS" BASIS,
  16. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. * See the License for the specific language governing permissions and
  18. * limitations under the License.
  19. */
  20. #ifdef HAVE_CONFIG_H
  21. #include "config.h"
  22. #endif
  23. #include <assert.h>
  24. #ifndef _WIN32
  25. #include <sched.h>
  26. #endif
  27. #include <winpr/handle.h>
  28. #include <winpr/thread.h>
  29. /**
  30. * api-ms-win-core-processthreads-l1-1-1.dll
  31. *
  32. * CreateRemoteThread
  33. * CreateRemoteThreadEx
  34. * CreateThread
  35. * DeleteProcThreadAttributeList
  36. * ExitThread
  37. * FlushInstructionCache
  38. * FlushProcessWriteBuffers
  39. * GetCurrentThread
  40. * GetCurrentThreadId
  41. * GetCurrentThreadStackLimits
  42. * GetExitCodeThread
  43. * GetPriorityClass
  44. * GetStartupInfoW
  45. * GetThreadContext
  46. * GetThreadId
  47. * GetThreadIdealProcessorEx
  48. * GetThreadPriority
  49. * GetThreadPriorityBoost
  50. * GetThreadTimes
  51. * InitializeProcThreadAttributeList
  52. * OpenThread
  53. * OpenThreadToken
  54. * QueryProcessAffinityUpdateMode
  55. * QueueUserAPC
  56. * ResumeThread
  57. * SetPriorityClass
  58. * SetThreadContext
  59. * SetThreadPriority
  60. * SetThreadPriorityBoost
  61. * SetThreadStackGuarantee
  62. * SetThreadToken
  63. * SuspendThread
  64. * SwitchToThread
  65. * TerminateThread
  66. * UpdateProcThreadAttribute
  67. */
  68. #ifndef _WIN32
  69. #include <winpr/crt.h>
  70. #include <winpr/platform.h>
  71. #ifdef HAVE_UNISTD_H
  72. #include <unistd.h>
  73. #endif
  74. #ifdef HAVE_SYS_EVENTFD_H
  75. #include <sys/eventfd.h>
  76. #endif
  77. #include <winpr/debug.h>
  78. #include <errno.h>
  79. #include <fcntl.h>
  80. #include <winpr/collections.h>
  81. #include "thread.h"
  82. #include "../handle/handle.h"
  83. #include "../log.h"
  84. #define TAG WINPR_TAG("thread")
  85. static wListDictionary* thread_list = NULL;
  86. static BOOL ThreadCloseHandle(HANDLE handle);
  87. static void cleanup_handle(void* obj);
  88. static BOOL ThreadIsHandled(HANDLE handle)
  89. {
  90. WINPR_THREAD* pThread = (WINPR_THREAD*)handle;
  91. if (!pThread || (pThread->Type != HANDLE_TYPE_THREAD))
  92. {
  93. SetLastError(ERROR_INVALID_HANDLE);
  94. return FALSE;
  95. }
  96. return TRUE;
  97. }
  98. static int ThreadGetFd(HANDLE handle)
  99. {
  100. WINPR_THREAD* pThread = (WINPR_THREAD*)handle;
  101. if (!ThreadIsHandled(handle))
  102. return -1;
  103. return pThread->pipe_fd[0];
  104. }
  105. static DWORD ThreadCleanupHandle(HANDLE handle)
  106. {
  107. WINPR_THREAD* thread = (WINPR_THREAD*)handle;
  108. if (!ThreadIsHandled(handle))
  109. return WAIT_FAILED;
  110. if (pthread_mutex_lock(&thread->mutex))
  111. return WAIT_FAILED;
  112. if (!thread->joined)
  113. {
  114. int status;
  115. status = pthread_join(thread->thread, NULL);
  116. if (status != 0)
  117. {
  118. WLog_ERR(TAG, "pthread_join failure: [%d] %s", status, strerror(status));
  119. pthread_mutex_unlock(&thread->mutex);
  120. return WAIT_FAILED;
  121. }
  122. else
  123. thread->joined = TRUE;
  124. }
  125. if (pthread_mutex_unlock(&thread->mutex))
  126. return WAIT_FAILED;
  127. return WAIT_OBJECT_0;
  128. }
  129. static HANDLE_OPS ops = { ThreadIsHandled,
  130. ThreadCloseHandle,
  131. ThreadGetFd,
  132. ThreadCleanupHandle,
  133. NULL,
  134. NULL,
  135. NULL,
  136. NULL,
  137. NULL,
  138. NULL,
  139. NULL,
  140. NULL,
  141. NULL,
  142. NULL,
  143. NULL,
  144. NULL,
  145. NULL,
  146. NULL,
  147. NULL,
  148. NULL };
  149. static void dump_thread(WINPR_THREAD* thread)
  150. {
  151. #if defined(WITH_DEBUG_THREADS)
  152. void* stack = winpr_backtrace(20);
  153. char** msg;
  154. size_t used, i;
  155. WLog_DBG(TAG, "Called from:");
  156. msg = winpr_backtrace_symbols(stack, &used);
  157. for (i = 0; i < used; i++)
  158. WLog_DBG(TAG, "[%" PRIdz "]: %s", i, msg[i]);
  159. free(msg);
  160. winpr_backtrace_free(stack);
  161. WLog_DBG(TAG, "Thread handle created still not closed!");
  162. msg = winpr_backtrace_symbols(thread->create_stack, &used);
  163. for (i = 0; i < used; i++)
  164. WLog_DBG(TAG, "[%" PRIdz "]: %s", i, msg[i]);
  165. free(msg);
  166. if (thread->started)
  167. {
  168. WLog_DBG(TAG, "Thread still running!");
  169. }
  170. else if (!thread->exit_stack)
  171. {
  172. WLog_DBG(TAG, "Thread suspended.");
  173. }
  174. else
  175. {
  176. WLog_DBG(TAG, "Thread exited at:");
  177. msg = winpr_backtrace_symbols(thread->exit_stack, &used);
  178. for (i = 0; i < used; i++)
  179. WLog_DBG(TAG, "[%" PRIdz "]: %s", i, msg[i]);
  180. free(msg);
  181. }
  182. #endif
  183. }
  184. /**
  185. * TODO: implement thread suspend/resume using pthreads
  186. * http://stackoverflow.com/questions/3140867/suspend-pthreads-without-using-condition
  187. */
  188. static BOOL set_event(WINPR_THREAD* thread)
  189. {
  190. int length;
  191. BOOL status = FALSE;
  192. #ifdef HAVE_SYS_EVENTFD_H
  193. eventfd_t val = 1;
  194. do
  195. {
  196. length = eventfd_write(thread->pipe_fd[0], val);
  197. } while ((length < 0) && (errno == EINTR));
  198. status = (length == 0) ? TRUE : FALSE;
  199. #else
  200. if (WaitForSingleObject(thread, 0) != WAIT_OBJECT_0)
  201. {
  202. length = write(thread->pipe_fd[1], "-", 1);
  203. if (length == 1)
  204. status = TRUE;
  205. }
  206. else
  207. {
  208. status = TRUE;
  209. }
  210. #endif
  211. return status;
  212. }
  213. static BOOL reset_event(WINPR_THREAD* thread)
  214. {
  215. int length;
  216. BOOL status = FALSE;
  217. #ifdef HAVE_SYS_EVENTFD_H
  218. eventfd_t value;
  219. do
  220. {
  221. length = eventfd_read(thread->pipe_fd[0], &value);
  222. } while ((length < 0) && (errno == EINTR));
  223. if ((length > 0) && (!status))
  224. status = TRUE;
  225. #else
  226. length = read(thread->pipe_fd[0], &length, 1);
  227. if ((length == 1) && (!status))
  228. status = TRUE;
  229. #endif
  230. return status;
  231. }
  232. static BOOL thread_compare(const void* a, const void* b)
  233. {
  234. const pthread_t* p1 = a;
  235. const pthread_t* p2 = b;
  236. BOOL rc = pthread_equal(*p1, *p2);
  237. return rc;
  238. }
  239. /* Thread launcher function responsible for registering
  240. * cleanup handlers and calling pthread_exit, if not done
  241. * in thread function. */
  242. static void* thread_launcher(void* arg)
  243. {
  244. DWORD rc = 0;
  245. WINPR_THREAD* thread = (WINPR_THREAD*)arg;
  246. LPTHREAD_START_ROUTINE fkt;
  247. if (!thread)
  248. {
  249. WLog_ERR(TAG, "Called with invalid argument %p", arg);
  250. goto exit;
  251. }
  252. if (!(fkt = thread->lpStartAddress))
  253. {
  254. WLog_ERR(TAG, "Thread function argument is %p", (void*)fkt);
  255. goto exit;
  256. }
  257. if (pthread_mutex_lock(&thread->threadIsReadyMutex))
  258. goto exit;
  259. if (!ListDictionary_Contains(thread_list, &thread->thread))
  260. {
  261. if (pthread_cond_wait(&thread->threadIsReady, &thread->threadIsReadyMutex) != 0)
  262. {
  263. WLog_ERR(TAG, "The thread could not be made ready");
  264. pthread_mutex_unlock(&thread->threadIsReadyMutex);
  265. goto exit;
  266. }
  267. }
  268. if (pthread_mutex_unlock(&thread->threadIsReadyMutex))
  269. goto exit;
  270. assert(ListDictionary_Contains(thread_list, &thread->thread));
  271. rc = fkt(thread->lpParameter);
  272. exit:
  273. if (thread)
  274. {
  275. if (!thread->exited)
  276. thread->dwExitCode = rc;
  277. set_event(thread);
  278. if (thread->detached || !thread->started)
  279. cleanup_handle(thread);
  280. }
  281. return NULL;
  282. }
  283. static BOOL winpr_StartThread(WINPR_THREAD* thread)
  284. {
  285. int inheritsched;
  286. struct sched_param param;
  287. int policy;
  288. int ret;
  289. pthread_attr_t attr;
  290. pthread_attr_init(&attr);
  291. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  292. /*start need root privilege or create thread would be failed.*/
  293. //PTHREAD_INHERIT_SCHED
  294. //ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
  295. //if (ret != 0) {
  296. // WLog_ERR(TAG, "pthread_attr_setinheritsched failed: %s", strerror(ret));
  297. // goto error;
  298. //}
  299. //param.sched_priority = 12;
  300. //policy = SCHED_FIFO;
  301. //ret = pthread_attr_setschedpolicy(&attr, policy);
  302. //if (ret != 0) {
  303. // WLog_ERR(TAG, "pthread_attr_setschedpolicy failed: %s", strerror(ret));
  304. // goto error;
  305. //}
  306. //ret = pthread_attr_setschedparam(&attr, &param);
  307. //if (ret != 0) {
  308. // WLog_ERR(TAG, "pthread_attr_setschedparam failed: %s", strerror(ret));
  309. // goto error;
  310. //}
  311. /*end*/
  312. if (thread->dwStackSize > 0)
  313. pthread_attr_setstacksize(&attr, (size_t)thread->dwStackSize);
  314. thread->started = TRUE;
  315. reset_event(thread);
  316. if (ret = pthread_create(&thread->thread, &attr, thread_launcher, thread))
  317. {
  318. WLog_ERR(TAG, "pthread_create failed: %s", strerror(ret));
  319. goto error;
  320. }
  321. if (pthread_mutex_lock(&thread->threadIsReadyMutex))
  322. goto error;
  323. if (!ListDictionary_Add(thread_list, &thread->thread, thread))
  324. {
  325. WLog_ERR(TAG, "failed to add the thread to the thread list");
  326. pthread_mutex_unlock(&thread->threadIsReadyMutex);
  327. goto error;
  328. }
  329. if (pthread_cond_signal(&thread->threadIsReady) != 0)
  330. {
  331. WLog_ERR(TAG, "failed to signal the thread was ready");
  332. pthread_mutex_unlock(&thread->threadIsReadyMutex);
  333. goto error;
  334. }
  335. if (pthread_mutex_unlock(&thread->threadIsReadyMutex))
  336. goto error;
  337. pthread_attr_destroy(&attr);
  338. dump_thread(thread);
  339. return TRUE;
  340. error:
  341. pthread_attr_destroy(&attr);
  342. return FALSE;
  343. }
  344. //HANDLE <-> WINPR_THREAD*
  345. //ThreadID <-> pthread_t or pthread_t*
  346. //Compare pthread_equal(*p1, *p2)
  347. HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize,
  348. LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter,
  349. DWORD dwCreationFlags, LPDWORD lpThreadId)
  350. {
  351. HANDLE handle;
  352. WINPR_THREAD* thread;
  353. thread = (WINPR_THREAD*)calloc(1, sizeof(WINPR_THREAD));
  354. if (!thread)
  355. return NULL;
  356. thread->dwStackSize = dwStackSize;
  357. thread->lpParameter = lpParameter;
  358. thread->lpStartAddress = lpStartAddress;
  359. thread->lpThreadAttributes = lpThreadAttributes;
  360. thread->ops = &ops;
  361. #if defined(WITH_DEBUG_THREADS)
  362. thread->create_stack = winpr_backtrace(20);
  363. dump_thread(thread);
  364. #endif
  365. thread->pipe_fd[0] = -1;
  366. thread->pipe_fd[1] = -1;
  367. #ifdef HAVE_SYS_EVENTFD_H
  368. thread->pipe_fd[0] = eventfd(0, EFD_NONBLOCK);
  369. if (thread->pipe_fd[0] < 0)
  370. {
  371. WLog_ERR(TAG, "failed to create thread pipe fd 0");
  372. goto error_pipefd0;
  373. }
  374. #else
  375. if (pipe(thread->pipe_fd) < 0)
  376. {
  377. WLog_ERR(TAG, "failed to create thread pipe");
  378. goto error_pipefd0;
  379. }
  380. {
  381. int flags = fcntl(thread->pipe_fd[0], F_GETFL);
  382. fcntl(thread->pipe_fd[0], F_SETFL, flags | O_NONBLOCK);
  383. }
  384. #endif
  385. if (pthread_mutex_init(&thread->mutex, 0) != 0)
  386. {
  387. WLog_ERR(TAG, "failed to initialize thread mutex");
  388. goto error_mutex;
  389. }
  390. if (pthread_mutex_init(&thread->threadIsReadyMutex, NULL) != 0)
  391. {
  392. WLog_ERR(TAG, "failed to initialize a mutex for a condition variable");
  393. goto error_thread_ready_mutex;
  394. }
  395. if (pthread_cond_init(&thread->threadIsReady, NULL) != 0)
  396. {
  397. WLog_ERR(TAG, "failed to initialize a condition variable");
  398. goto error_thread_ready;
  399. }
  400. WINPR_HANDLE_SET_TYPE_AND_MODE(thread, HANDLE_TYPE_THREAD, WINPR_FD_READ);
  401. handle = (HANDLE)thread;
  402. assert(handle != THREAD_CUR_ONE_HANDLE);
  403. if (!thread_list)
  404. {
  405. thread_list = ListDictionary_New(TRUE);
  406. if (!thread_list)
  407. {
  408. WLog_ERR(TAG, "Couldn't create global thread list");
  409. goto error_thread_list;
  410. }
  411. thread_list->objectKey.fnObjectEquals = thread_compare;
  412. }
  413. if (!(dwCreationFlags & CREATE_SUSPENDED))
  414. {
  415. if (!winpr_StartThread(thread))
  416. goto error_thread_list;
  417. }
  418. else
  419. {
  420. if (!set_event(thread))
  421. goto error_thread_list;
  422. }
  423. return handle;
  424. error_thread_list:
  425. pthread_cond_destroy(&thread->threadIsReady);
  426. error_thread_ready:
  427. pthread_mutex_destroy(&thread->threadIsReadyMutex);
  428. error_thread_ready_mutex:
  429. pthread_mutex_destroy(&thread->mutex);
  430. error_mutex:
  431. if (thread->pipe_fd[1] >= 0)
  432. close(thread->pipe_fd[1]);
  433. if (thread->pipe_fd[0] >= 0)
  434. close(thread->pipe_fd[0]);
  435. error_pipefd0:
  436. free(thread);
  437. return NULL;
  438. }
  439. void cleanup_handle(void* obj)
  440. {
  441. int rc;
  442. WINPR_THREAD* thread = (WINPR_THREAD*)obj;
  443. rc = pthread_cond_destroy(&thread->threadIsReady);
  444. if (rc)
  445. WLog_ERR(TAG, "failed to destroy a condition variable [%d] %s (%d)", rc, strerror(errno),
  446. errno);
  447. rc = pthread_mutex_destroy(&thread->threadIsReadyMutex);
  448. if (rc)
  449. WLog_ERR(TAG, "failed to destroy a condition variable mutex [%d] %s (%d)", rc,
  450. strerror(errno), errno);
  451. rc = pthread_mutex_destroy(&thread->mutex);
  452. if (rc)
  453. WLog_ERR(TAG, "failed to destroy mutex [%d] %s (%d)", rc, strerror(errno), errno);
  454. if (thread->pipe_fd[0] >= 0)
  455. close(thread->pipe_fd[0]);
  456. if (thread->pipe_fd[1] >= 0)
  457. close(thread->pipe_fd[1]);
  458. if (thread_list && ListDictionary_Contains(thread_list, &thread->thread))
  459. ListDictionary_Remove(thread_list, &thread->thread);
  460. #if defined(WITH_DEBUG_THREADS)
  461. if (thread->create_stack)
  462. winpr_backtrace_free(thread->create_stack);
  463. if (thread->exit_stack)
  464. winpr_backtrace_free(thread->exit_stack);
  465. #endif
  466. free(thread);
  467. }
  468. BOOL ThreadCloseHandle(HANDLE handle)
  469. {
  470. WINPR_THREAD* thread = (WINPR_THREAD*)handle;
  471. if (!thread_list)
  472. {
  473. WLog_ERR(TAG, "Thread list does not exist, check call!");
  474. dump_thread(thread);
  475. }
  476. else if (!ListDictionary_Contains(thread_list, &thread->thread))
  477. {
  478. WLog_ERR(TAG, "Thread list does not contain this thread! check call!");
  479. dump_thread(thread);
  480. }
  481. else
  482. {
  483. ListDictionary_Lock(thread_list);
  484. dump_thread(thread);
  485. if ((thread->started) && (WaitForSingleObject(thread, 0) != WAIT_OBJECT_0))
  486. {
  487. WLog_DBG(TAG, "Thread running, setting to detached state!");
  488. thread->detached = TRUE;
  489. pthread_detach(thread->thread);
  490. }
  491. else
  492. {
  493. cleanup_handle(thread);
  494. }
  495. ListDictionary_Unlock(thread_list);
  496. if (ListDictionary_Count(thread_list) < 1)
  497. {
  498. ListDictionary_Free(thread_list);
  499. thread_list = NULL;
  500. }
  501. }
  502. return TRUE;
  503. }
  504. HANDLE CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes,
  505. SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
  506. LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId)
  507. {
  508. WLog_ERR(TAG, "%s: not implemented", __FUNCTION__);
  509. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  510. return NULL;
  511. }
  512. VOID ExitThread(DWORD dwExitCode)
  513. {
  514. DWORD rc;
  515. pthread_t tid = pthread_self();
  516. if (!thread_list)
  517. {
  518. WLog_ERR(TAG, "%s called without existing thread list!", __FUNCTION__);
  519. #if defined(WITH_DEBUG_THREADS)
  520. DumpThreadHandles();
  521. #endif
  522. pthread_exit(0);
  523. }
  524. else if (!ListDictionary_Contains(thread_list, &tid))
  525. {
  526. WLog_ERR(TAG, "function called, but no matching entry in thread list!");
  527. #if defined(WITH_DEBUG_THREADS)
  528. DumpThreadHandles();
  529. #endif
  530. pthread_exit(0);
  531. }
  532. else
  533. {
  534. WINPR_THREAD* thread;
  535. ListDictionary_Lock(thread_list);
  536. thread = ListDictionary_GetItemValue(thread_list, &tid);
  537. assert(thread);
  538. thread->exited = TRUE;
  539. thread->dwExitCode = dwExitCode;
  540. #if defined(WITH_DEBUG_THREADS)
  541. thread->exit_stack = winpr_backtrace(20);
  542. #endif
  543. ListDictionary_Unlock(thread_list);
  544. set_event(thread);
  545. rc = thread->dwExitCode;
  546. if (thread->detached || !thread->started)
  547. cleanup_handle(thread);
  548. pthread_exit((void*)(size_t)rc);
  549. }
  550. }
  551. BOOL GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode)
  552. {
  553. ULONG Type;
  554. WINPR_HANDLE* Object;
  555. WINPR_THREAD* thread;
  556. if (!winpr_Handle_GetInfo(hThread, &Type, &Object))
  557. return FALSE;
  558. thread = (WINPR_THREAD*)Object;
  559. *lpExitCode = thread->dwExitCode;
  560. return TRUE;
  561. }
  562. HANDLE _GetCurrentThread(VOID)
  563. {
  564. HANDLE hdl = THREAD_CUR_ONE_HANDLE;
  565. pthread_t tid = pthread_self();
  566. if (!thread_list)
  567. {
  568. WLog_ERR(TAG, "%s called without existing thread list!", __FUNCTION__);
  569. #if defined(WITH_DEBUG_THREADS)
  570. DumpThreadHandles();
  571. #endif
  572. }
  573. else if (!ListDictionary_Contains(thread_list, &tid))
  574. {
  575. WLog_ERR(TAG, "function called, but no matching entry in thread list!");
  576. #if defined(WITH_DEBUG_THREADS)
  577. DumpThreadHandles();
  578. #endif
  579. }
  580. else
  581. {
  582. hdl = ListDictionary_GetItemValue(thread_list, &tid);
  583. }
  584. return hdl;
  585. }
  586. DWORD GetCurrentThreadId(VOID)
  587. {
  588. pthread_t tid;
  589. tid = pthread_self();
  590. /* Since pthread_t can be 64-bits on some systems, take just the */
  591. /* lower 32-bits of it for the thread ID returned by this function. */
  592. return (DWORD)tid & 0xffffffffUL;
  593. }
  594. DWORD ResumeThread(HANDLE hThread)
  595. {
  596. ULONG Type;
  597. WINPR_HANDLE* Object;
  598. WINPR_THREAD* thread;
  599. if (!winpr_Handle_GetInfo(hThread, &Type, &Object))
  600. return (DWORD)-1;
  601. thread = (WINPR_THREAD*)Object;
  602. if (pthread_mutex_lock(&thread->mutex))
  603. return (DWORD)-1;
  604. if (!thread->started)
  605. {
  606. if (!winpr_StartThread(thread))
  607. {
  608. pthread_mutex_unlock(&thread->mutex);
  609. return (DWORD)-1;
  610. }
  611. }
  612. else
  613. WLog_WARN(TAG, "Thread already started!");
  614. if (pthread_mutex_unlock(&thread->mutex))
  615. return (DWORD)-1;
  616. return 0;
  617. }
  618. DWORD SuspendThread(HANDLE hThread)
  619. {
  620. WLog_ERR(TAG, "%s: not implemented", __FUNCTION__);
  621. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  622. return (DWORD)-1;
  623. }
  624. BOOL SwitchToThread(VOID)
  625. {
  626. /**
  627. * Note: on some operating systems sched_yield is a stub returning -1.
  628. * usleep should at least trigger a context switch if any thread is waiting.
  629. */
  630. if (sched_yield() != 0)
  631. usleep(1);
  632. return TRUE;
  633. }
  634. BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode)
  635. {
  636. ULONG Type;
  637. WINPR_HANDLE* Object;
  638. WINPR_THREAD* thread;
  639. if (!winpr_Handle_GetInfo(hThread, &Type, &Object))
  640. return FALSE;
  641. thread = (WINPR_THREAD*)Object;
  642. thread->exited = TRUE;
  643. thread->dwExitCode = dwExitCode;
  644. if (pthread_mutex_lock(&thread->mutex))
  645. return FALSE;
  646. #ifndef ANDROID
  647. pthread_cancel(thread->thread);
  648. #else
  649. WLog_ERR(TAG, "Function not supported on this platform!");
  650. #endif
  651. if (pthread_mutex_unlock(&thread->mutex))
  652. return FALSE;
  653. set_event(thread);
  654. return TRUE;
  655. }
  656. /*
  657. * Gifur add and implement it.
  658. */
  659. HANDLE OpenThread(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId)
  660. {
  661. HANDLE hdl = NULL;
  662. pthread_t tid = (pthread_t)dwThreadId;
  663. if(bInheritHandle) {
  664. WLog_WARN(TAG, "bInheritHandle is not supported now.");
  665. }
  666. if (!thread_list)
  667. {
  668. WLog_ERR(TAG, "%s called without existing thread list!", __FUNCTION__);
  669. #if defined(WITH_DEBUG_THREADS)
  670. DumpThreadHandles();
  671. #endif
  672. }
  673. else if (!ListDictionary_Contains(thread_list, &tid))
  674. {
  675. WLog_ERR(TAG, "function called, but no matching entry in thread list!");
  676. #if defined(WITH_DEBUG_THREADS)
  677. DumpThreadHandles();
  678. #endif
  679. }
  680. else
  681. {
  682. hdl = ListDictionary_GetItemValue(thread_list, &tid);
  683. }
  684. return hdl;
  685. }
  686. /*Gifur implement and need to confirm its validity*/
  687. BOOL SetThreadPriority(HANDLE hThread, int nPriority)
  688. {
  689. BOOL result = TRUE;
  690. ULONG Type;
  691. WINPR_HANDLE* Object;
  692. WINPR_THREAD* thread = NULL;
  693. struct sched_param param;
  694. pthread_attr_t attr;
  695. pthread_t cur_thread;
  696. int policy = 0;
  697. int max_prio_for_policy = 0;
  698. int min_prio_for_policy = 0;
  699. int ret = 0;
  700. if (!winpr_Handle_GetInfo(hThread, &Type, &Object))
  701. {
  702. if (hThread == THREAD_CUR_ONE_HANDLE) {
  703. WLog_DBG(TAG, "current thread flag.");
  704. cur_thread = pthread_self();
  705. }
  706. else {
  707. WLog_ERR(TAG, "get thread handle information failed!");
  708. return FALSE;
  709. }
  710. }
  711. else {
  712. thread = (WINPR_THREAD*)Object;
  713. cur_thread = thread->thread;
  714. }
  715. #if 0
  716. /*https://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_setschedprio.html*/
  717. pthread_attr_init(&attr);
  718. pthread_attr_getschedpolicy(&attr, &policy);
  719. if (nPriority == THREAD_PRIORITY_HIGHEST) {
  720. max_prio_for_policy = sched_get_priority_max(policy);
  721. /*
  722. * set the scheduling priority for the thread to prio
  723. */
  724. if(0 != pthread_setschedprio(cur_thread, max_prio_for_policy)) {
  725. result = FALSE;
  726. }
  727. }
  728. pthread_attr_destroy(&attr);
  729. #else
  730. /*it might be preferable conceptually to solve this problem.*/
  731. ret = pthread_getschedparam(cur_thread, &policy, &param);
  732. if(0 != ret)
  733. {
  734. WLog_ERR(TAG, "get thread schedule param failed, err: %d", ret);
  735. return FALSE;
  736. }
  737. WLog_DBG(TAG, "the thread policy: %d, priority: %d.", policy, param.sched_priority);
  738. /*for scheduled under one of : SCHED_OTHER, SCHED_IDLE, SCHED_BATCH
  739. *sched_priority is not used and it must be 0.
  740. */
  741. if(policy == SCHED_OTHER
  742. #ifdef __USE_GNU
  743. || policy == SCHED_IDLE || policy == SCHED_BATCH
  744. #endif
  745. ) {
  746. policy = SCHED_FIFO;
  747. }
  748. max_prio_for_policy = sched_get_priority_max(policy);
  749. min_prio_for_policy = sched_get_priority_min(policy);
  750. if (nPriority == THREAD_PRIORITY_HIGHEST) {
  751. param.sched_priority = max_prio_for_policy;
  752. } else if (nPriority == THREAD_PRIORITY_ABOVE_NORMAL) {
  753. param.sched_priority = (max_prio_for_policy + min_prio_for_policy) / 2;
  754. } else
  755. {
  756. WLog_ERR(TAG, "current priority %d is not support!", nPriority);
  757. return FALSE;
  758. }
  759. /*
  760. * EPERM:
  761. * the caller does not have appropriate permission to set either the scheduling
  762. * parameters or the scheduling policy of the specified thread.
  763. */
  764. ret = pthread_setschedparam(cur_thread, policy, &param);
  765. if (0 != ret) {
  766. WLog_ERR(TAG, "set scheduled param failed! policy: %d, priority: %d, err: %d",
  767. policy, param.sched_priority, ret);
  768. result = FALSE;
  769. }
  770. #endif
  771. return result;
  772. }
  773. #if defined(WITH_DEBUG_THREADS)
  774. VOID DumpThreadHandles(void)
  775. {
  776. char** msg;
  777. size_t used, i;
  778. void* stack = winpr_backtrace(20);
  779. WLog_DBG(TAG, "---------------- Called from ----------------------------");
  780. msg = winpr_backtrace_symbols(stack, &used);
  781. for (i = 0; i < used; i++)
  782. {
  783. WLog_DBG(TAG, "[%" PRIdz "]: %s", i, msg[i]);
  784. }
  785. free(msg);
  786. winpr_backtrace_free(stack);
  787. WLog_DBG(TAG, "---------------- Start Dumping thread handles -----------");
  788. if (!thread_list)
  789. {
  790. WLog_DBG(TAG, "All threads properly shut down and disposed of.");
  791. }
  792. else
  793. {
  794. ULONG_PTR* keys = NULL;
  795. ListDictionary_Lock(thread_list);
  796. int x, count = ListDictionary_GetKeys(thread_list, &keys);
  797. WLog_DBG(TAG, "Dumping %d elements", count);
  798. for (x = 0; x < count; x++)
  799. {
  800. WINPR_THREAD* thread = ListDictionary_GetItemValue(thread_list, (void*)keys[x]);
  801. WLog_DBG(TAG, "Thread [%d] handle created still not closed!", x);
  802. msg = winpr_backtrace_symbols(thread->create_stack, &used);
  803. for (i = 0; i < used; i++)
  804. {
  805. WLog_DBG(TAG, "[%" PRIdz "]: %s", i, msg[i]);
  806. }
  807. free(msg);
  808. if (thread->started)
  809. {
  810. WLog_DBG(TAG, "Thread [%d] still running!", x);
  811. }
  812. else
  813. {
  814. WLog_DBG(TAG, "Thread [%d] exited at:", x);
  815. msg = winpr_backtrace_symbols(thread->exit_stack, &used);
  816. for (i = 0; i < used; i++)
  817. WLog_DBG(TAG, "[%" PRIdz "]: %s", i, msg[i]);
  818. free(msg);
  819. }
  820. }
  821. free(keys);
  822. ListDictionary_Unlock(thread_list);
  823. }
  824. WLog_DBG(TAG, "---------------- End Dumping thread handles -------------");
  825. }
  826. #endif
  827. #endif