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.

388 lines
9.2KB

  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/sysctl.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_broadcast (&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. struct kinfo_proc info;
  185. int m[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
  186. size_t sz = sizeof (info);
  187. sysctl (m, 4, &info, &sz, 0, 0);
  188. testResult = (info.kp_proc.p_flag & P_TRACED) == P_TRACED ? 1 : -1;
  189. }
  190. return testResult > 0;
  191. }
  192. bool JUCE_CALLTYPE Process::isRunningUnderDebugger() throw()
  193. {
  194. return juce_isRunningUnderDebugger();
  195. }
  196. void Process::raisePrivilege()
  197. {
  198. jassertfalse
  199. }
  200. void Process::lowerPrivilege()
  201. {
  202. jassertfalse
  203. }
  204. void Process::terminate()
  205. {
  206. ExitToShell();
  207. }
  208. void Process::setPriority (ProcessPriority p)
  209. {
  210. // xxx
  211. }
  212. void* Process::loadDynamicLibrary (const String& name)
  213. {
  214. // xxx needs to use bundles
  215. FSSpec fs;
  216. if (PlatformUtilities::makeFSSpecFromPath (&fs, name))
  217. {
  218. CFragConnectionID connID;
  219. Ptr mainPtr;
  220. Str255 errorMessage;
  221. Str63 nm;
  222. PlatformUtilities::copyToStr63 (nm, name);
  223. const OSErr err = GetDiskFragment (&fs, 0, kCFragGoesToEOF, nm, kReferenceCFrag, &connID, &mainPtr, errorMessage);
  224. if (err == noErr)
  225. return (void*)connID;
  226. }
  227. return 0;
  228. }
  229. void Process::freeDynamicLibrary (void* handle)
  230. {
  231. if (handle != 0)
  232. CloseConnection ((CFragConnectionID*)&handle);
  233. }
  234. void* Process::getProcedureEntryPoint (void* h, const String& procedureName)
  235. {
  236. if (h != 0)
  237. {
  238. CFragSymbolClass cl;
  239. Ptr ptr;
  240. Str255 name;
  241. PlatformUtilities::copyToStr255 (name, procedureName);
  242. if (FindSymbol ((CFragConnectionID) h, name, &ptr, &cl) == noErr)
  243. {
  244. return ptr;
  245. }
  246. }
  247. return 0;
  248. }
  249. //==============================================================================
  250. InterProcessLock::InterProcessLock (const String& name_) throw()
  251. : internal (0),
  252. name (name_),
  253. reentrancyLevel (0)
  254. {
  255. const File tempDir (File::getSpecialLocation (File::tempDirectory));
  256. const File temp (tempDir.getChildFile (name));
  257. temp.create();
  258. internal = (void*) open (temp.getFullPathName().toUTF8(), O_NONBLOCK | O_RDONLY);
  259. }
  260. InterProcessLock::~InterProcessLock() throw()
  261. {
  262. while (reentrancyLevel > 0)
  263. this->exit();
  264. close ((int) internal);
  265. }
  266. bool InterProcessLock::enter (const int timeOutMillisecs) throw()
  267. {
  268. if (internal == 0)
  269. return false;
  270. if (reentrancyLevel != 0)
  271. return true;
  272. if (timeOutMillisecs <= 0)
  273. {
  274. if (flock ((int) internal,
  275. timeOutMillisecs < 0 ? LOCK_EX
  276. : (LOCK_EX | LOCK_NB)) == 0)
  277. {
  278. ++reentrancyLevel;
  279. return true;
  280. }
  281. }
  282. else
  283. {
  284. const int64 endTime = Time::currentTimeMillis() + timeOutMillisecs;
  285. for (;;)
  286. {
  287. if (flock ((int) internal, LOCK_EX | LOCK_NB) == 0)
  288. {
  289. ++reentrancyLevel;
  290. return true;
  291. }
  292. if (Time::currentTimeMillis() >= endTime)
  293. break;
  294. Thread::sleep (10);
  295. }
  296. }
  297. return false;
  298. }
  299. void InterProcessLock::exit() throw()
  300. {
  301. if (reentrancyLevel > 0 && internal != 0)
  302. {
  303. --reentrancyLevel;
  304. const int result = flock ((int) internal, LOCK_UN);
  305. (void) result;
  306. jassert (result == 0);
  307. }
  308. }
  309. END_JUCE_NAMESPACE