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.

365 lines
9.0KB

  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 <Carbon/Carbon.h>
  28. BEGIN_JUCE_NAMESPACE
  29. #include "../../../src/juce_core/threads/juce_CriticalSection.h"
  30. #include "../../../src/juce_core/threads/juce_WaitableEvent.h"
  31. #include "../../../src/juce_core/threads/juce_Thread.h"
  32. #include "../../../src/juce_core/threads/juce_Process.h"
  33. #include "../../../src/juce_core/threads/juce_InterProcessLock.h"
  34. #include "../../../src/juce_core/misc/juce_PlatformUtilities.h"
  35. #include "../../../src/juce_core/io/files/juce_File.h"
  36. //==============================================================================
  37. CriticalSection::CriticalSection() throw()
  38. {
  39. pthread_mutexattr_t atts;
  40. pthread_mutexattr_init (&atts);
  41. pthread_mutexattr_settype (&atts, PTHREAD_MUTEX_RECURSIVE);
  42. pthread_mutex_init (&internal, &atts);
  43. }
  44. CriticalSection::~CriticalSection() throw()
  45. {
  46. pthread_mutex_destroy (&internal);
  47. }
  48. void CriticalSection::enter() const throw()
  49. {
  50. pthread_mutex_lock (&internal);
  51. }
  52. bool CriticalSection::tryEnter() const throw()
  53. {
  54. return pthread_mutex_trylock (&internal) == 0;
  55. }
  56. void CriticalSection::exit() const throw()
  57. {
  58. pthread_mutex_unlock (&internal);
  59. }
  60. //==============================================================================
  61. struct EventStruct
  62. {
  63. pthread_cond_t condition;
  64. pthread_mutex_t mutex;
  65. bool triggered;
  66. };
  67. WaitableEvent::WaitableEvent() throw()
  68. {
  69. EventStruct* const es = new EventStruct();
  70. es->triggered = false;
  71. pthread_cond_init (&es->condition, 0);
  72. pthread_mutex_init (&es->mutex, 0);
  73. internal = es;
  74. }
  75. WaitableEvent::~WaitableEvent() throw()
  76. {
  77. EventStruct* const es = (EventStruct*) internal;
  78. pthread_cond_destroy (&es->condition);
  79. pthread_mutex_destroy (&es->mutex);
  80. delete es;
  81. }
  82. bool WaitableEvent::wait (const int timeOutMillisecs) const throw()
  83. {
  84. EventStruct* const es = (EventStruct*) internal;
  85. bool ok = true;
  86. pthread_mutex_lock (&es->mutex);
  87. if (! es->triggered)
  88. {
  89. if (timeOutMillisecs < 0)
  90. {
  91. pthread_cond_wait (&es->condition, &es->mutex);
  92. }
  93. else
  94. {
  95. struct timespec time;
  96. time.tv_sec = timeOutMillisecs / 1000;
  97. time.tv_nsec = (timeOutMillisecs % 1000) * 1000000;
  98. pthread_cond_timedwait_relative_np (&es->condition, &es->mutex, &time);
  99. }
  100. ok = es->triggered;
  101. }
  102. es->triggered = false;
  103. pthread_mutex_unlock (&es->mutex);
  104. return ok;
  105. }
  106. void WaitableEvent::signal() const throw()
  107. {
  108. EventStruct* const es = (EventStruct*) internal;
  109. pthread_mutex_lock (&es->mutex);
  110. es->triggered = true;
  111. pthread_cond_signal (&es->condition);
  112. pthread_mutex_unlock (&es->mutex);
  113. }
  114. void WaitableEvent::reset() const throw()
  115. {
  116. EventStruct* const es = (EventStruct*) internal;
  117. pthread_mutex_lock (&es->mutex);
  118. es->triggered = false;
  119. pthread_mutex_unlock (&es->mutex);
  120. }
  121. //==============================================================================
  122. void JUCE_API juce_threadEntryPoint (void*);
  123. void* threadEntryProc (void* userData) throw()
  124. {
  125. juce_threadEntryPoint (userData);
  126. return 0;
  127. }
  128. void* juce_createThread (void* userData) throw()
  129. {
  130. pthread_t handle = 0;
  131. if (pthread_create (&handle, 0, threadEntryProc, userData) == 0)
  132. {
  133. pthread_detach (handle);
  134. return (void*) handle;
  135. }
  136. return 0;
  137. }
  138. void juce_killThread (void* handle) throw()
  139. {
  140. if (handle != 0)
  141. pthread_cancel ((pthread_t) handle);
  142. }
  143. void juce_setCurrentThreadName (const String& /*name*/) throw()
  144. {
  145. }
  146. int Thread::getCurrentThreadId() throw()
  147. {
  148. return (int) pthread_self();
  149. }
  150. void juce_setThreadPriority (void* handle, int priority) throw()
  151. {
  152. if (handle == 0)
  153. handle = (void*) pthread_self();
  154. struct sched_param param;
  155. int policy;
  156. pthread_getschedparam ((pthread_t) handle, &policy, &param);
  157. param.sched_priority = jlimit (1, 127, 1 + (priority * 126) / 11);
  158. pthread_setschedparam ((pthread_t) handle, policy, &param);
  159. }
  160. void Thread::yield() throw()
  161. {
  162. sched_yield();
  163. }
  164. void Thread::setCurrentThreadAffinityMask (const uint32 affinityMask) throw()
  165. {
  166. // xxx
  167. jassertfalse
  168. }
  169. void JUCE_CALLTYPE Thread::sleep (int millisecs) throw()
  170. {
  171. struct timespec time;
  172. time.tv_sec = millisecs / 1000;
  173. time.tv_nsec = (millisecs % 1000) * 1000000;
  174. nanosleep (&time, 0);
  175. }
  176. //==============================================================================
  177. void Process::raisePrivilege()
  178. {
  179. jassertfalse
  180. }
  181. void Process::lowerPrivilege()
  182. {
  183. jassertfalse
  184. }
  185. void Process::terminate()
  186. {
  187. ExitToShell();
  188. }
  189. void Process::setPriority (ProcessPriority p)
  190. {
  191. // xxx
  192. }
  193. void* Process::loadDynamicLibrary (const String& name)
  194. {
  195. // xxx needs to use bundles
  196. FSSpec fs;
  197. if (PlatformUtilities::makeFSSpecFromPath (&fs, name))
  198. {
  199. CFragConnectionID connID;
  200. Ptr mainPtr;
  201. Str255 errorMessage;
  202. Str63 nm;
  203. PlatformUtilities::copyToStr63 (nm, name);
  204. const OSErr err = GetDiskFragment (&fs, 0, kCFragGoesToEOF, nm, kReferenceCFrag, &connID, &mainPtr, errorMessage);
  205. if (err == noErr)
  206. return (void*)connID;
  207. }
  208. return 0;
  209. }
  210. void Process::freeDynamicLibrary (void* handle)
  211. {
  212. if (handle != 0)
  213. CloseConnection ((CFragConnectionID*)&handle);
  214. }
  215. void* Process::getProcedureEntryPoint (void* h, const String& procedureName)
  216. {
  217. if (h != 0)
  218. {
  219. CFragSymbolClass cl;
  220. Ptr ptr;
  221. Str255 name;
  222. PlatformUtilities::copyToStr255 (name, procedureName);
  223. if (FindSymbol ((CFragConnectionID) h, name, &ptr, &cl) == noErr)
  224. {
  225. return ptr;
  226. }
  227. }
  228. return 0;
  229. }
  230. //==============================================================================
  231. InterProcessLock::InterProcessLock (const String& name_) throw()
  232. : internal (0),
  233. name (name_),
  234. reentrancyLevel (0)
  235. {
  236. const File tempDir (File::getSpecialLocation (File::tempDirectory));
  237. const File temp (tempDir.getChildFile (name));
  238. temp.create();
  239. internal = (void*) open (temp.getFullPathName().toUTF8(), O_NONBLOCK | O_RDONLY);
  240. }
  241. InterProcessLock::~InterProcessLock() throw()
  242. {
  243. while (reentrancyLevel > 0)
  244. this->exit();
  245. close ((int) internal);
  246. }
  247. bool InterProcessLock::enter (const int timeOutMillisecs) throw()
  248. {
  249. if (internal == 0)
  250. return false;
  251. if (reentrancyLevel != 0)
  252. return true;
  253. if (timeOutMillisecs <= 0)
  254. {
  255. if (flock ((int) internal,
  256. timeOutMillisecs < 0 ? LOCK_EX
  257. : (LOCK_EX | LOCK_NB)) == 0)
  258. {
  259. ++reentrancyLevel;
  260. return true;
  261. }
  262. }
  263. else
  264. {
  265. const int64 endTime = Time::currentTimeMillis() + timeOutMillisecs;
  266. for (;;)
  267. {
  268. if (flock ((int) internal, LOCK_EX | LOCK_NB) == 0)
  269. {
  270. ++reentrancyLevel;
  271. return true;
  272. }
  273. if (Time::currentTimeMillis() >= endTime)
  274. break;
  275. Thread::sleep (10);
  276. }
  277. }
  278. return false;
  279. }
  280. void InterProcessLock::exit() throw()
  281. {
  282. if (reentrancyLevel > 0 && internal != 0)
  283. {
  284. --reentrancyLevel;
  285. const int result = flock ((int) internal, LOCK_UN);
  286. (void) result;
  287. jassert (result == 0);
  288. }
  289. }
  290. END_JUCE_NAMESPACE