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.

508 lines
13KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-9 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. /*
  19. This file contains posix routines that are common to both the Linux and Mac builds.
  20. It gets included directly in the cpp files for these platforms.
  21. */
  22. //==============================================================================
  23. CriticalSection::CriticalSection() throw()
  24. {
  25. pthread_mutexattr_t atts;
  26. pthread_mutexattr_init (&atts);
  27. pthread_mutexattr_settype (&atts, PTHREAD_MUTEX_RECURSIVE);
  28. pthread_mutex_init (&internal, &atts);
  29. }
  30. CriticalSection::~CriticalSection() throw()
  31. {
  32. pthread_mutex_destroy (&internal);
  33. }
  34. void CriticalSection::enter() const throw()
  35. {
  36. pthread_mutex_lock (&internal);
  37. }
  38. bool CriticalSection::tryEnter() const throw()
  39. {
  40. return pthread_mutex_trylock (&internal) == 0;
  41. }
  42. void CriticalSection::exit() const throw()
  43. {
  44. pthread_mutex_unlock (&internal);
  45. }
  46. //==============================================================================
  47. struct EventStruct
  48. {
  49. pthread_cond_t condition;
  50. pthread_mutex_t mutex;
  51. bool triggered;
  52. };
  53. WaitableEvent::WaitableEvent() throw()
  54. {
  55. EventStruct* const es = new EventStruct();
  56. es->triggered = false;
  57. pthread_cond_init (&es->condition, 0);
  58. pthread_mutex_init (&es->mutex, 0);
  59. internal = es;
  60. }
  61. WaitableEvent::~WaitableEvent() throw()
  62. {
  63. EventStruct* const es = (EventStruct*) internal;
  64. pthread_cond_destroy (&es->condition);
  65. pthread_mutex_destroy (&es->mutex);
  66. delete es;
  67. }
  68. bool WaitableEvent::wait (const int timeOutMillisecs) const throw()
  69. {
  70. EventStruct* const es = (EventStruct*) internal;
  71. pthread_mutex_lock (&es->mutex);
  72. if (timeOutMillisecs < 0)
  73. {
  74. while (! es->triggered)
  75. pthread_cond_wait (&es->condition, &es->mutex);
  76. }
  77. else
  78. {
  79. while (! es->triggered)
  80. {
  81. struct timeval t;
  82. gettimeofday (&t, 0);
  83. struct timespec time;
  84. time.tv_sec = t.tv_sec + (timeOutMillisecs / 1000);
  85. time.tv_nsec = (t.tv_usec + ((timeOutMillisecs % 1000) * 1000)) * 1000;
  86. if (time.tv_nsec >= 1000000000)
  87. {
  88. time.tv_nsec -= 1000000000;
  89. time.tv_sec++;
  90. }
  91. if (pthread_cond_timedwait (&es->condition, &es->mutex, &time) == ETIMEDOUT)
  92. {
  93. pthread_mutex_unlock (&es->mutex);
  94. return false;
  95. }
  96. }
  97. }
  98. es->triggered = false;
  99. pthread_mutex_unlock (&es->mutex);
  100. return true;
  101. }
  102. void WaitableEvent::signal() const throw()
  103. {
  104. EventStruct* const es = (EventStruct*) internal;
  105. pthread_mutex_lock (&es->mutex);
  106. es->triggered = true;
  107. pthread_cond_broadcast (&es->condition);
  108. pthread_mutex_unlock (&es->mutex);
  109. }
  110. void WaitableEvent::reset() const throw()
  111. {
  112. EventStruct* const es = (EventStruct*) internal;
  113. pthread_mutex_lock (&es->mutex);
  114. es->triggered = false;
  115. pthread_mutex_unlock (&es->mutex);
  116. }
  117. //==============================================================================
  118. void JUCE_CALLTYPE Thread::sleep (int millisecs) throw()
  119. {
  120. struct timespec time;
  121. time.tv_sec = millisecs / 1000;
  122. time.tv_nsec = (millisecs % 1000) * 1000000;
  123. nanosleep (&time, 0);
  124. }
  125. //==============================================================================
  126. const tchar File::separator = T('/');
  127. const tchar* File::separatorString = T("/");
  128. //==============================================================================
  129. bool juce_copyFile (const String& s, const String& d) throw();
  130. static bool juce_stat (const String& fileName, struct stat& info) throw()
  131. {
  132. return fileName.isNotEmpty()
  133. && (stat (fileName.toUTF8(), &info) == 0);
  134. }
  135. bool juce_isDirectory (const String& fileName) throw()
  136. {
  137. struct stat info;
  138. return fileName.isEmpty()
  139. || (juce_stat (fileName, info)
  140. && ((info.st_mode & S_IFDIR) != 0));
  141. }
  142. bool juce_fileExists (const String& fileName, const bool dontCountDirectories) throw()
  143. {
  144. if (fileName.isEmpty())
  145. return false;
  146. const char* const fileNameUTF8 = fileName.toUTF8();
  147. bool exists = access (fileNameUTF8, F_OK) == 0;
  148. if (exists && dontCountDirectories)
  149. {
  150. struct stat info;
  151. const int res = stat (fileNameUTF8, &info);
  152. if (res == 0 && (info.st_mode & S_IFDIR) != 0)
  153. exists = false;
  154. }
  155. return exists;
  156. }
  157. int64 juce_getFileSize (const String& fileName) throw()
  158. {
  159. struct stat info;
  160. return juce_stat (fileName, info) ? info.st_size : 0;
  161. }
  162. //==============================================================================
  163. bool juce_canWriteToFile (const String& fileName) throw()
  164. {
  165. return access (fileName.toUTF8(), W_OK) == 0;
  166. }
  167. bool juce_deleteFile (const String& fileName) throw()
  168. {
  169. if (juce_isDirectory (fileName))
  170. return rmdir ((const char*) fileName.toUTF8()) == 0;
  171. else
  172. return remove ((const char*) fileName.toUTF8()) == 0;
  173. }
  174. bool juce_moveFile (const String& source, const String& dest) throw()
  175. {
  176. if (rename (source.toUTF8(), dest.toUTF8()) == 0)
  177. return true;
  178. if (juce_canWriteToFile (source)
  179. && juce_copyFile (source, dest))
  180. {
  181. if (juce_deleteFile (source))
  182. return true;
  183. juce_deleteFile (dest);
  184. }
  185. return false;
  186. }
  187. void juce_createDirectory (const String& fileName) throw()
  188. {
  189. mkdir (fileName.toUTF8(), 0777);
  190. }
  191. void* juce_fileOpen (const String& fileName, bool forWriting) throw()
  192. {
  193. int flags = O_RDONLY;
  194. if (forWriting)
  195. {
  196. if (juce_fileExists (fileName, false))
  197. {
  198. const int f = open ((const char*) fileName.toUTF8(), O_RDWR, 00644);
  199. if (f != -1)
  200. lseek (f, 0, SEEK_END);
  201. return (void*) f;
  202. }
  203. else
  204. {
  205. flags = O_RDWR + O_CREAT;
  206. }
  207. }
  208. return (void*) open ((const char*) fileName.toUTF8(), flags, 00644);
  209. }
  210. void juce_fileClose (void* handle) throw()
  211. {
  212. if (handle != 0)
  213. close ((int) (pointer_sized_int) handle);
  214. }
  215. int juce_fileRead (void* handle, void* buffer, int size) throw()
  216. {
  217. if (handle != 0)
  218. return read ((int) (pointer_sized_int) handle, buffer, size);
  219. return 0;
  220. }
  221. int juce_fileWrite (void* handle, const void* buffer, int size) throw()
  222. {
  223. if (handle != 0)
  224. return write ((int) (pointer_sized_int) handle, buffer, size);
  225. return 0;
  226. }
  227. int64 juce_fileSetPosition (void* handle, int64 pos) throw()
  228. {
  229. if (handle != 0 && lseek ((int) (pointer_sized_int) handle, pos, SEEK_SET) == pos)
  230. return pos;
  231. return -1;
  232. }
  233. int64 juce_fileGetPosition (void* handle) throw()
  234. {
  235. if (handle != 0)
  236. return lseek ((int) (pointer_sized_int) handle, 0, SEEK_CUR);
  237. else
  238. return -1;
  239. }
  240. void juce_fileFlush (void* handle) throw()
  241. {
  242. if (handle != 0)
  243. fsync ((int) (pointer_sized_int) handle);
  244. }
  245. const File juce_getExecutableFile()
  246. {
  247. Dl_info exeInfo;
  248. dladdr ((const void*) juce_getExecutableFile, &exeInfo);
  249. return File (exeInfo.dli_fname);
  250. }
  251. //==============================================================================
  252. // if this file doesn't exist, find a parent of it that does..
  253. static bool doStatFS (const File* file, struct statfs& result) throw()
  254. {
  255. File f (*file);
  256. for (int i = 5; --i >= 0;)
  257. {
  258. if (f.exists())
  259. break;
  260. f = f.getParentDirectory();
  261. }
  262. return statfs (f.getFullPathName().toUTF8(), &result) == 0;
  263. }
  264. int64 File::getBytesFreeOnVolume() const throw()
  265. {
  266. struct statfs buf;
  267. if (doStatFS (this, buf))
  268. return (int64) buf.f_bsize * (int64) buf.f_bavail; // Note: this returns space available to non-super user
  269. return 0;
  270. }
  271. int64 File::getVolumeTotalSize() const throw()
  272. {
  273. struct statfs buf;
  274. if (doStatFS (this, buf))
  275. return (int64) buf.f_bsize * (int64) buf.f_blocks;
  276. return 0;
  277. }
  278. const String juce_getVolumeLabel (const String& filenameOnVolume,
  279. int& volumeSerialNumber) throw()
  280. {
  281. volumeSerialNumber = 0;
  282. #if JUCE_MAC
  283. struct VolAttrBuf
  284. {
  285. u_int32_t length;
  286. attrreference_t mountPointRef;
  287. char mountPointSpace [MAXPATHLEN];
  288. } attrBuf;
  289. struct attrlist attrList;
  290. zerostruct (attrList);
  291. attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
  292. attrList.volattr = ATTR_VOL_INFO | ATTR_VOL_NAME;
  293. File f (filenameOnVolume);
  294. for (;;)
  295. {
  296. if (getattrlist ((const char*) f.getFullPathName().toUTF8(),
  297. &attrList, &attrBuf, sizeof(attrBuf), 0) == 0)
  298. {
  299. return String::fromUTF8 (((const uint8*) &attrBuf.mountPointRef) + attrBuf.mountPointRef.attr_dataoffset,
  300. (int) attrBuf.mountPointRef.attr_length);
  301. }
  302. const File parent (f.getParentDirectory());
  303. if (f == parent)
  304. break;
  305. f = parent;
  306. }
  307. #endif
  308. return String::empty;
  309. }
  310. //==============================================================================
  311. void juce_runSystemCommand (const String& command)
  312. {
  313. int result = system ((const char*) command.toUTF8());
  314. (void) result;
  315. }
  316. const String juce_getOutputFromCommand (const String& command)
  317. {
  318. // slight bodge here, as we just pipe the output into a temp file and read it...
  319. const File tempFile (File::getSpecialLocation (File::tempDirectory)
  320. .getNonexistentChildFile (String::toHexString (Random::getSystemRandom().nextInt()), ".tmp", false));
  321. juce_runSystemCommand (command + " > " + tempFile.getFullPathName());
  322. String result (tempFile.loadFileAsString());
  323. tempFile.deleteFile();
  324. return result;
  325. }
  326. //==============================================================================
  327. #if JUCE_64BIT
  328. #define filedesc ((long long) internal)
  329. #else
  330. #define filedesc ((int) internal)
  331. #endif
  332. InterProcessLock::InterProcessLock (const String& name_) throw()
  333. : internal (0),
  334. name (name_),
  335. reentrancyLevel (0)
  336. {
  337. #if JUCE_MAC
  338. // (don't use getSpecialLocation() to avoid the temp folder being different for each app)
  339. const File temp (File (T("~/Library/Caches/Juce")).getChildFile (name));
  340. #else
  341. const File temp (File::getSpecialLocation (File::tempDirectory).getChildFile (name));
  342. #endif
  343. temp.create();
  344. internal = (void*) open (temp.getFullPathName().toUTF8(), O_RDWR);
  345. }
  346. InterProcessLock::~InterProcessLock() throw()
  347. {
  348. while (reentrancyLevel > 0)
  349. this->exit();
  350. close (filedesc);
  351. }
  352. bool InterProcessLock::enter (const int timeOutMillisecs) throw()
  353. {
  354. if (internal == 0)
  355. return false;
  356. if (reentrancyLevel != 0)
  357. return true;
  358. const int64 endTime = Time::currentTimeMillis() + timeOutMillisecs;
  359. struct flock fl;
  360. zerostruct (fl);
  361. fl.l_whence = SEEK_SET;
  362. fl.l_type = F_WRLCK;
  363. for (;;)
  364. {
  365. const int result = fcntl (filedesc, F_SETLK, &fl);
  366. if (result >= 0)
  367. {
  368. ++reentrancyLevel;
  369. return true;
  370. }
  371. if (errno != EINTR)
  372. {
  373. if (timeOutMillisecs == 0
  374. || (timeOutMillisecs > 0 && Time::currentTimeMillis() >= endTime))
  375. break;
  376. Thread::sleep (10);
  377. }
  378. }
  379. return false;
  380. }
  381. void InterProcessLock::exit() throw()
  382. {
  383. if (reentrancyLevel > 0 && internal != 0)
  384. {
  385. --reentrancyLevel;
  386. struct flock fl;
  387. zerostruct (fl);
  388. fl.l_whence = SEEK_SET;
  389. fl.l_type = F_UNLCK;
  390. for (;;)
  391. {
  392. const int result = fcntl (filedesc, F_SETLKW, &fl);
  393. if (result >= 0 || errno != EINTR)
  394. break;
  395. }
  396. }
  397. }