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.

511 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. bool ok = true;
  72. pthread_mutex_lock (&es->mutex);
  73. if (timeOutMillisecs < 0)
  74. {
  75. while (! es->triggered)
  76. pthread_cond_wait (&es->condition, &es->mutex);
  77. }
  78. else
  79. {
  80. while (! es->triggered)
  81. {
  82. struct timeval t;
  83. gettimeofday (&t, 0);
  84. struct timespec time;
  85. time.tv_sec = t.tv_sec + (timeOutMillisecs / 1000);
  86. time.tv_nsec = (t.tv_usec + ((timeOutMillisecs % 1000) * 1000)) * 1000;
  87. if (time.tv_nsec >= 1000000000)
  88. {
  89. time.tv_nsec -= 1000000000;
  90. time.tv_sec++;
  91. }
  92. if (pthread_cond_timedwait (&es->condition, &es->mutex, &time) == ETIMEDOUT)
  93. {
  94. ok = false;
  95. break;
  96. }
  97. }
  98. }
  99. es->triggered = false;
  100. pthread_mutex_unlock (&es->mutex);
  101. return ok;
  102. }
  103. void WaitableEvent::signal() const throw()
  104. {
  105. EventStruct* const es = (EventStruct*) internal;
  106. pthread_mutex_lock (&es->mutex);
  107. es->triggered = true;
  108. pthread_cond_broadcast (&es->condition);
  109. pthread_mutex_unlock (&es->mutex);
  110. }
  111. void WaitableEvent::reset() const throw()
  112. {
  113. EventStruct* const es = (EventStruct*) internal;
  114. pthread_mutex_lock (&es->mutex);
  115. es->triggered = false;
  116. pthread_mutex_unlock (&es->mutex);
  117. }
  118. //==============================================================================
  119. void JUCE_CALLTYPE Thread::sleep (int millisecs) throw()
  120. {
  121. struct timespec time;
  122. time.tv_sec = millisecs / 1000;
  123. time.tv_nsec = (millisecs % 1000) * 1000000;
  124. nanosleep (&time, 0);
  125. }
  126. //==============================================================================
  127. const tchar File::separator = T('/');
  128. const tchar* File::separatorString = T("/");
  129. //==============================================================================
  130. bool juce_copyFile (const String& s, const String& d) throw();
  131. static bool juce_stat (const String& fileName, struct stat& info) throw()
  132. {
  133. return fileName.isNotEmpty()
  134. && (stat (fileName.toUTF8(), &info) == 0);
  135. }
  136. bool juce_isDirectory (const String& fileName) throw()
  137. {
  138. struct stat info;
  139. return fileName.isEmpty()
  140. || (juce_stat (fileName, info)
  141. && ((info.st_mode & S_IFDIR) != 0));
  142. }
  143. bool juce_fileExists (const String& fileName, const bool dontCountDirectories) throw()
  144. {
  145. if (fileName.isEmpty())
  146. return false;
  147. const char* const fileNameUTF8 = fileName.toUTF8();
  148. bool exists = access (fileNameUTF8, F_OK) == 0;
  149. if (exists && dontCountDirectories)
  150. {
  151. struct stat info;
  152. const int res = stat (fileNameUTF8, &info);
  153. if (res == 0 && (info.st_mode & S_IFDIR) != 0)
  154. exists = false;
  155. }
  156. return exists;
  157. }
  158. int64 juce_getFileSize (const String& fileName) throw()
  159. {
  160. struct stat info;
  161. return juce_stat (fileName, info) ? info.st_size : 0;
  162. }
  163. //==============================================================================
  164. bool juce_canWriteToFile (const String& fileName) throw()
  165. {
  166. return access (fileName.toUTF8(), W_OK) == 0;
  167. }
  168. bool juce_deleteFile (const String& fileName) throw()
  169. {
  170. if (juce_isDirectory (fileName))
  171. return rmdir ((const char*) fileName.toUTF8()) == 0;
  172. else
  173. return remove ((const char*) fileName.toUTF8()) == 0;
  174. }
  175. bool juce_moveFile (const String& source, const String& dest) throw()
  176. {
  177. if (rename (source.toUTF8(), dest.toUTF8()) == 0)
  178. return true;
  179. if (juce_canWriteToFile (source)
  180. && juce_copyFile (source, dest))
  181. {
  182. if (juce_deleteFile (source))
  183. return true;
  184. juce_deleteFile (dest);
  185. }
  186. return false;
  187. }
  188. void juce_createDirectory (const String& fileName) throw()
  189. {
  190. mkdir (fileName.toUTF8(), 0777);
  191. }
  192. void* juce_fileOpen (const String& fileName, bool forWriting) throw()
  193. {
  194. int flags = O_RDONLY;
  195. if (forWriting)
  196. {
  197. if (juce_fileExists (fileName, false))
  198. {
  199. const int f = open ((const char*) fileName.toUTF8(), O_RDWR, 00644);
  200. if (f != -1)
  201. lseek (f, 0, SEEK_END);
  202. return (void*) f;
  203. }
  204. else
  205. {
  206. flags = O_RDWR + O_CREAT;
  207. }
  208. }
  209. return (void*) open ((const char*) fileName.toUTF8(), flags, 00644);
  210. }
  211. void juce_fileClose (void* handle) throw()
  212. {
  213. if (handle != 0)
  214. close ((int) (pointer_sized_int) handle);
  215. }
  216. int juce_fileRead (void* handle, void* buffer, int size) throw()
  217. {
  218. if (handle != 0)
  219. return read ((int) (pointer_sized_int) handle, buffer, size);
  220. return 0;
  221. }
  222. int juce_fileWrite (void* handle, const void* buffer, int size) throw()
  223. {
  224. if (handle != 0)
  225. return write ((int) (pointer_sized_int) handle, buffer, size);
  226. return 0;
  227. }
  228. int64 juce_fileSetPosition (void* handle, int64 pos) throw()
  229. {
  230. if (handle != 0 && lseek ((int) (pointer_sized_int) handle, pos, SEEK_SET) == pos)
  231. return pos;
  232. return -1;
  233. }
  234. int64 juce_fileGetPosition (void* handle) throw()
  235. {
  236. if (handle != 0)
  237. return lseek ((int) (pointer_sized_int) handle, 0, SEEK_CUR);
  238. else
  239. return -1;
  240. }
  241. void juce_fileFlush (void* handle) throw()
  242. {
  243. if (handle != 0)
  244. fsync ((int) (pointer_sized_int) handle);
  245. }
  246. const File juce_getExecutableFile()
  247. {
  248. Dl_info exeInfo;
  249. dladdr ((const void*) juce_getExecutableFile, &exeInfo);
  250. return File (exeInfo.dli_fname);
  251. }
  252. //==============================================================================
  253. // if this file doesn't exist, find a parent of it that does..
  254. static bool doStatFS (const File* file, struct statfs& result) throw()
  255. {
  256. File f (*file);
  257. for (int i = 5; --i >= 0;)
  258. {
  259. if (f.exists())
  260. break;
  261. f = f.getParentDirectory();
  262. }
  263. return statfs (f.getFullPathName().toUTF8(), &result) == 0;
  264. }
  265. int64 File::getBytesFreeOnVolume() const throw()
  266. {
  267. struct statfs buf;
  268. if (doStatFS (this, buf))
  269. return (int64) buf.f_bsize * (int64) buf.f_bavail; // Note: this returns space available to non-super user
  270. return 0;
  271. }
  272. int64 File::getVolumeTotalSize() const throw()
  273. {
  274. struct statfs buf;
  275. if (doStatFS (this, buf))
  276. return (int64) buf.f_bsize * (int64) buf.f_blocks;
  277. return 0;
  278. }
  279. const String juce_getVolumeLabel (const String& filenameOnVolume,
  280. int& volumeSerialNumber) throw()
  281. {
  282. volumeSerialNumber = 0;
  283. #if JUCE_MAC
  284. struct VolAttrBuf
  285. {
  286. u_int32_t length;
  287. attrreference_t mountPointRef;
  288. char mountPointSpace [MAXPATHLEN];
  289. } attrBuf;
  290. struct attrlist attrList;
  291. zerostruct (attrList);
  292. attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
  293. attrList.volattr = ATTR_VOL_INFO | ATTR_VOL_NAME;
  294. File f (filenameOnVolume);
  295. for (;;)
  296. {
  297. if (getattrlist ((const char*) f.getFullPathName().toUTF8(),
  298. &attrList, &attrBuf, sizeof(attrBuf), 0) == 0)
  299. {
  300. return String::fromUTF8 (((const uint8*) &attrBuf.mountPointRef) + attrBuf.mountPointRef.attr_dataoffset,
  301. (int) attrBuf.mountPointRef.attr_length);
  302. }
  303. const File parent (f.getParentDirectory());
  304. if (f == parent)
  305. break;
  306. f = parent;
  307. }
  308. #endif
  309. return String::empty;
  310. }
  311. //==============================================================================
  312. void juce_runSystemCommand (const String& command)
  313. {
  314. int result = system ((const char*) command.toUTF8());
  315. (void) result;
  316. }
  317. const String juce_getOutputFromCommand (const String& command)
  318. {
  319. // slight bodge here, as we just pipe the output into a temp file and read it...
  320. const File tempFile (File::getSpecialLocation (File::tempDirectory)
  321. .getNonexistentChildFile (String::toHexString (Random::getSystemRandom().nextInt()), ".tmp", false));
  322. juce_runSystemCommand (command + " > " + tempFile.getFullPathName());
  323. String result (tempFile.loadFileAsString());
  324. tempFile.deleteFile();
  325. return result;
  326. }
  327. //==============================================================================
  328. #if JUCE_64BIT
  329. #define filedesc ((long long) internal)
  330. #else
  331. #define filedesc ((int) internal)
  332. #endif
  333. InterProcessLock::InterProcessLock (const String& name_) throw()
  334. : internal (0),
  335. name (name_),
  336. reentrancyLevel (0)
  337. {
  338. #if JUCE_MAC
  339. // (don't use getSpecialLocation() to avoid the temp folder being different for each app)
  340. const File temp (File (T("~/Library/Caches/Juce")).getChildFile (name));
  341. #else
  342. const File temp (File::getSpecialLocation (File::tempDirectory).getChildFile (name));
  343. #endif
  344. temp.create();
  345. internal = (void*) open (temp.getFullPathName().toUTF8(), O_RDWR);
  346. }
  347. InterProcessLock::~InterProcessLock() throw()
  348. {
  349. while (reentrancyLevel > 0)
  350. this->exit();
  351. close (filedesc);
  352. }
  353. bool InterProcessLock::enter (const int timeOutMillisecs) throw()
  354. {
  355. if (internal == 0)
  356. return false;
  357. if (reentrancyLevel != 0)
  358. return true;
  359. const int64 endTime = Time::currentTimeMillis() + timeOutMillisecs;
  360. struct flock fl;
  361. zerostruct (fl);
  362. fl.l_whence = SEEK_SET;
  363. fl.l_type = F_WRLCK;
  364. for (;;)
  365. {
  366. const int result = fcntl (filedesc, F_SETLK, &fl);
  367. if (result >= 0)
  368. {
  369. ++reentrancyLevel;
  370. return true;
  371. }
  372. if (errno != EINTR)
  373. {
  374. if (timeOutMillisecs == 0
  375. || (timeOutMillisecs > 0 && Time::currentTimeMillis() >= endTime))
  376. break;
  377. Thread::sleep (10);
  378. }
  379. }
  380. return false;
  381. }
  382. void InterProcessLock::exit() throw()
  383. {
  384. if (reentrancyLevel > 0 && internal != 0)
  385. {
  386. --reentrancyLevel;
  387. struct flock fl;
  388. zerostruct (fl);
  389. fl.l_whence = SEEK_SET;
  390. fl.l_type = F_UNLCK;
  391. for (;;)
  392. {
  393. const int result = fcntl (filedesc, F_SETLKW, &fl);
  394. if (result >= 0 || errno != EINTR)
  395. break;
  396. }
  397. }
  398. }