The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

387 lines
9.5KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #include "../../../src/juce_core/basics/juce_StandardHeader.h"
  24. #include <pthread.h>
  25. #include <sched.h>
  26. #include <sys/file.h>
  27. #include <sys/types.h>
  28. #include <sys/ptrace.h>
  29. #include <Carbon/Carbon.h>
  30. BEGIN_JUCE_NAMESPACE
  31. #include "../../../src/juce_core/threads/juce_CriticalSection.h"
  32. #include "../../../src/juce_core/threads/juce_WaitableEvent.h"
  33. #include "../../../src/juce_core/threads/juce_Thread.h"
  34. #include "../../../src/juce_core/threads/juce_Process.h"
  35. #include "../../../src/juce_core/threads/juce_InterProcessLock.h"
  36. #include "../../../src/juce_core/misc/juce_PlatformUtilities.h"
  37. #include "../../../src/juce_core/io/files/juce_File.h"
  38. //==============================================================================
  39. CriticalSection::CriticalSection() throw()
  40. {
  41. pthread_mutexattr_t atts;
  42. pthread_mutexattr_init (&atts);
  43. pthread_mutexattr_settype (&atts, PTHREAD_MUTEX_RECURSIVE);
  44. pthread_mutex_init (&internal, &atts);
  45. }
  46. CriticalSection::~CriticalSection() throw()
  47. {
  48. pthread_mutex_destroy (&internal);
  49. }
  50. void CriticalSection::enter() const throw()
  51. {
  52. pthread_mutex_lock (&internal);
  53. }
  54. bool CriticalSection::tryEnter() const throw()
  55. {
  56. return pthread_mutex_trylock (&internal) == 0;
  57. }
  58. void CriticalSection::exit() const throw()
  59. {
  60. pthread_mutex_unlock (&internal);
  61. }
  62. //==============================================================================
  63. struct EventStruct
  64. {
  65. pthread_cond_t condition;
  66. pthread_mutex_t mutex;
  67. bool triggered;
  68. };
  69. WaitableEvent::WaitableEvent() throw()
  70. {
  71. EventStruct* const es = new EventStruct();
  72. es->triggered = false;
  73. pthread_cond_init (&es->condition, 0);
  74. pthread_mutex_init (&es->mutex, 0);
  75. internal = es;
  76. }
  77. WaitableEvent::~WaitableEvent() throw()
  78. {
  79. EventStruct* const es = (EventStruct*) internal;
  80. pthread_cond_destroy (&es->condition);
  81. pthread_mutex_destroy (&es->mutex);
  82. delete es;
  83. }
  84. bool WaitableEvent::wait (const int timeOutMillisecs) const throw()
  85. {
  86. EventStruct* const es = (EventStruct*) internal;
  87. bool ok = true;
  88. pthread_mutex_lock (&es->mutex);
  89. if (! es->triggered)
  90. {
  91. if (timeOutMillisecs < 0)
  92. {
  93. pthread_cond_wait (&es->condition, &es->mutex);
  94. }
  95. else
  96. {
  97. struct timespec time;
  98. time.tv_sec = timeOutMillisecs / 1000;
  99. time.tv_nsec = (timeOutMillisecs % 1000) * 1000000;
  100. pthread_cond_timedwait_relative_np (&es->condition, &es->mutex, &time);
  101. }
  102. ok = es->triggered;
  103. }
  104. es->triggered = false;
  105. pthread_mutex_unlock (&es->mutex);
  106. return ok;
  107. }
  108. void WaitableEvent::signal() const throw()
  109. {
  110. EventStruct* const es = (EventStruct*) internal;
  111. pthread_mutex_lock (&es->mutex);
  112. es->triggered = true;
  113. pthread_cond_signal (&es->condition);
  114. pthread_mutex_unlock (&es->mutex);
  115. }
  116. void WaitableEvent::reset() const throw()
  117. {
  118. EventStruct* const es = (EventStruct*) internal;
  119. pthread_mutex_lock (&es->mutex);
  120. es->triggered = false;
  121. pthread_mutex_unlock (&es->mutex);
  122. }
  123. //==============================================================================
  124. void JUCE_API juce_threadEntryPoint (void*);
  125. void* threadEntryProc (void* userData) throw()
  126. {
  127. juce_threadEntryPoint (userData);
  128. return 0;
  129. }
  130. void* juce_createThread (void* userData) throw()
  131. {
  132. pthread_t handle = 0;
  133. if (pthread_create (&handle, 0, threadEntryProc, userData) == 0)
  134. {
  135. pthread_detach (handle);
  136. return (void*) handle;
  137. }
  138. return 0;
  139. }
  140. void juce_killThread (void* handle) throw()
  141. {
  142. if (handle != 0)
  143. pthread_cancel ((pthread_t) handle);
  144. }
  145. void juce_setCurrentThreadName (const String& /*name*/) throw()
  146. {
  147. }
  148. int Thread::getCurrentThreadId() throw()
  149. {
  150. return (int) pthread_self();
  151. }
  152. void juce_setThreadPriority (void* handle, int priority) throw()
  153. {
  154. if (handle == 0)
  155. handle = (void*) pthread_self();
  156. struct sched_param param;
  157. int policy;
  158. pthread_getschedparam ((pthread_t) handle, &policy, &param);
  159. param.sched_priority = jlimit (1, 127, 1 + (priority * 126) / 11);
  160. pthread_setschedparam ((pthread_t) handle, policy, &param);
  161. }
  162. void Thread::yield() throw()
  163. {
  164. sched_yield();
  165. }
  166. void Thread::setCurrentThreadAffinityMask (const uint32 affinityMask) throw()
  167. {
  168. // xxx
  169. jassertfalse
  170. }
  171. void JUCE_CALLTYPE Thread::sleep (int millisecs) throw()
  172. {
  173. struct timespec time;
  174. time.tv_sec = millisecs / 1000;
  175. time.tv_nsec = (millisecs % 1000) * 1000000;
  176. nanosleep (&time, 0);
  177. }
  178. //==============================================================================
  179. bool JUCE_CALLTYPE juce_isRunningUnderDebugger() throw()
  180. {
  181. static char testResult = 0;
  182. if (testResult == 0)
  183. {
  184. testResult = (ptrace (PT_TRACE_ME, 0, 0, 0) < 0) ? 1 : -1;
  185. if (testResult < 0)
  186. ptrace (PT_DETACH, 0, (caddr_t) 1, 0);
  187. }
  188. return testResult > 0;
  189. }
  190. bool JUCE_CALLTYPE Process::isRunningUnderDebugger() throw()
  191. {
  192. return juce_isRunningUnderDebugger();
  193. }
  194. void Process::raisePrivilege()
  195. {
  196. jassertfalse
  197. }
  198. void Process::lowerPrivilege()
  199. {
  200. jassertfalse
  201. }
  202. void Process::terminate()
  203. {
  204. ExitToShell();
  205. }
  206. void Process::setPriority (ProcessPriority p)
  207. {
  208. // xxx
  209. }
  210. void* Process::loadDynamicLibrary (const String& name)
  211. {
  212. // xxx needs to use bundles
  213. FSSpec fs;
  214. if (PlatformUtilities::makeFSSpecFromPath (&fs, name))
  215. {
  216. CFragConnectionID connID;
  217. Ptr mainPtr;
  218. Str255 errorMessage;
  219. Str63 nm;
  220. PlatformUtilities::copyToStr63 (nm, name);
  221. const OSErr err = GetDiskFragment (&fs, 0, kCFragGoesToEOF, nm, kReferenceCFrag, &connID, &mainPtr, errorMessage);
  222. if (err == noErr)
  223. return (void*)connID;
  224. }
  225. return 0;
  226. }
  227. void Process::freeDynamicLibrary (void* handle)
  228. {
  229. if (handle != 0)
  230. CloseConnection ((CFragConnectionID*)&handle);
  231. }
  232. void* Process::getProcedureEntryPoint (void* h, const String& procedureName)
  233. {
  234. if (h != 0)
  235. {
  236. CFragSymbolClass cl;
  237. Ptr ptr;
  238. Str255 name;
  239. PlatformUtilities::copyToStr255 (name, procedureName);
  240. if (FindSymbol ((CFragConnectionID) h, name, &ptr, &cl) == noErr)
  241. {
  242. return ptr;
  243. }
  244. }
  245. return 0;
  246. }
  247. //==============================================================================
  248. InterProcessLock::InterProcessLock (const String& name_) throw()
  249. : internal (0),
  250. name (name_),
  251. reentrancyLevel (0)
  252. {
  253. const File tempDir (File::getSpecialLocation (File::tempDirectory));
  254. const File temp (tempDir.getChildFile (name));
  255. temp.create();
  256. internal = (void*) open (temp.getFullPathName().toUTF8(), O_NONBLOCK | O_RDONLY);
  257. }
  258. InterProcessLock::~InterProcessLock() throw()
  259. {
  260. while (reentrancyLevel > 0)
  261. this->exit();
  262. close ((int) internal);
  263. }
  264. bool InterProcessLock::enter (const int timeOutMillisecs) throw()
  265. {
  266. if (internal == 0)
  267. return false;
  268. if (reentrancyLevel != 0)
  269. return true;
  270. if (timeOutMillisecs <= 0)
  271. {
  272. if (flock ((int) internal,
  273. timeOutMillisecs < 0 ? LOCK_EX
  274. : (LOCK_EX | LOCK_NB)) == 0)
  275. {
  276. ++reentrancyLevel;
  277. return true;
  278. }
  279. }
  280. else
  281. {
  282. const int64 endTime = Time::currentTimeMillis() + timeOutMillisecs;
  283. for (;;)
  284. {
  285. if (flock ((int) internal, LOCK_EX | LOCK_NB) == 0)
  286. {
  287. ++reentrancyLevel;
  288. return true;
  289. }
  290. if (Time::currentTimeMillis() >= endTime)
  291. break;
  292. Thread::sleep (10);
  293. }
  294. }
  295. return false;
  296. }
  297. void InterProcessLock::exit() throw()
  298. {
  299. if (reentrancyLevel > 0 && internal != 0)
  300. {
  301. --reentrancyLevel;
  302. const int result = flock ((int) internal, LOCK_UN);
  303. (void) result;
  304. jassert (result == 0);
  305. }
  306. }
  307. END_JUCE_NAMESPACE