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.

470 lines
12KB

  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. /*
  24. This file contains posix routines that are common to both the Linux and Mac builds.
  25. It gets included directly in the cpp files for these platforms.
  26. */
  27. //==============================================================================
  28. CriticalSection::CriticalSection() throw()
  29. {
  30. pthread_mutexattr_t atts;
  31. pthread_mutexattr_init (&atts);
  32. pthread_mutexattr_settype (&atts, PTHREAD_MUTEX_RECURSIVE);
  33. pthread_mutex_init (&internal, &atts);
  34. }
  35. CriticalSection::~CriticalSection() throw()
  36. {
  37. pthread_mutex_destroy (&internal);
  38. }
  39. void CriticalSection::enter() const throw()
  40. {
  41. pthread_mutex_lock (&internal);
  42. }
  43. bool CriticalSection::tryEnter() const throw()
  44. {
  45. return pthread_mutex_trylock (&internal) == 0;
  46. }
  47. void CriticalSection::exit() const throw()
  48. {
  49. pthread_mutex_unlock (&internal);
  50. }
  51. //==============================================================================
  52. struct EventStruct
  53. {
  54. pthread_cond_t condition;
  55. pthread_mutex_t mutex;
  56. bool triggered;
  57. };
  58. WaitableEvent::WaitableEvent() throw()
  59. {
  60. EventStruct* const es = new EventStruct();
  61. es->triggered = false;
  62. pthread_cond_init (&es->condition, 0);
  63. pthread_mutex_init (&es->mutex, 0);
  64. internal = es;
  65. }
  66. WaitableEvent::~WaitableEvent() throw()
  67. {
  68. EventStruct* const es = (EventStruct*) internal;
  69. pthread_cond_destroy (&es->condition);
  70. pthread_mutex_destroy (&es->mutex);
  71. delete es;
  72. }
  73. bool WaitableEvent::wait (const int timeOutMillisecs) const throw()
  74. {
  75. EventStruct* const es = (EventStruct*) internal;
  76. bool ok = true;
  77. pthread_mutex_lock (&es->mutex);
  78. if (! es->triggered)
  79. {
  80. if (timeOutMillisecs < 0)
  81. {
  82. pthread_cond_wait (&es->condition, &es->mutex);
  83. }
  84. else
  85. {
  86. struct timespec time;
  87. #if JUCE_MAC
  88. time.tv_sec = timeOutMillisecs / 1000;
  89. time.tv_nsec = (timeOutMillisecs % 1000) * 1000000;
  90. pthread_cond_timedwait_relative_np (&es->condition, &es->mutex, &time);
  91. #else
  92. struct timeval t;
  93. int timeout = 0;
  94. gettimeofday (&t, 0);
  95. time.tv_sec = t.tv_sec + (timeOutMillisecs / 1000);
  96. time.tv_nsec = (t.tv_usec + ((timeOutMillisecs % 1000) * 1000)) * 1000;
  97. while (time.tv_nsec >= 1000000000)
  98. {
  99. time.tv_nsec -= 1000000000;
  100. time.tv_sec++;
  101. }
  102. while (! timeout)
  103. {
  104. timeout = pthread_cond_timedwait (&es->condition, &es->mutex, &time);
  105. if (! timeout)
  106. // Success
  107. break;
  108. if (timeout == EINTR)
  109. // Go round again
  110. timeout = 0;
  111. }
  112. #endif
  113. }
  114. ok = es->triggered;
  115. }
  116. es->triggered = false;
  117. pthread_mutex_unlock (&es->mutex);
  118. return ok;
  119. }
  120. void WaitableEvent::signal() const throw()
  121. {
  122. EventStruct* const es = (EventStruct*) internal;
  123. pthread_mutex_lock (&es->mutex);
  124. es->triggered = true;
  125. pthread_cond_broadcast (&es->condition);
  126. pthread_mutex_unlock (&es->mutex);
  127. }
  128. void WaitableEvent::reset() const throw()
  129. {
  130. EventStruct* const es = (EventStruct*) internal;
  131. pthread_mutex_lock (&es->mutex);
  132. es->triggered = false;
  133. pthread_mutex_unlock (&es->mutex);
  134. }
  135. //==============================================================================
  136. void JUCE_CALLTYPE Thread::sleep (int millisecs) throw()
  137. {
  138. struct timespec time;
  139. time.tv_sec = millisecs / 1000;
  140. time.tv_nsec = (millisecs % 1000) * 1000000;
  141. nanosleep (&time, 0);
  142. }
  143. //==============================================================================
  144. const tchar File::separator = T('/');
  145. const tchar* File::separatorString = T("/");
  146. //==============================================================================
  147. bool juce_copyFile (const String& s, const String& d) throw();
  148. static bool juce_stat (const String& fileName, struct stat& info) throw()
  149. {
  150. return fileName.isNotEmpty()
  151. && (stat (fileName.toUTF8(), &info) == 0);
  152. }
  153. bool juce_isDirectory (const String& fileName) throw()
  154. {
  155. struct stat info;
  156. return fileName.isEmpty()
  157. || (juce_stat (fileName, info)
  158. && ((info.st_mode & S_IFDIR) != 0));
  159. }
  160. bool juce_fileExists (const String& fileName, const bool dontCountDirectories) throw()
  161. {
  162. if (fileName.isEmpty())
  163. return false;
  164. const char* const fileNameUTF8 = fileName.toUTF8();
  165. bool exists = access (fileNameUTF8, F_OK) == 0;
  166. if (exists && dontCountDirectories)
  167. {
  168. struct stat info;
  169. const int res = stat (fileNameUTF8, &info);
  170. if (res == 0 && (info.st_mode & S_IFDIR) != 0)
  171. exists = false;
  172. }
  173. return exists;
  174. }
  175. int64 juce_getFileSize (const String& fileName) throw()
  176. {
  177. struct stat info;
  178. return juce_stat (fileName, info) ? info.st_size : 0;
  179. }
  180. //==============================================================================
  181. bool juce_canWriteToFile (const String& fileName) throw()
  182. {
  183. return access (fileName.toUTF8(), W_OK) == 0;
  184. }
  185. bool juce_deleteFile (const String& fileName) throw()
  186. {
  187. const char* const fileNameUTF8 = fileName.toUTF8();
  188. if (juce_isDirectory (fileName))
  189. return rmdir (fileNameUTF8) == 0;
  190. else
  191. return remove (fileNameUTF8) == 0;
  192. }
  193. bool juce_moveFile (const String& source, const String& dest) throw()
  194. {
  195. if (rename (source.toUTF8(), dest.toUTF8()) == 0)
  196. return true;
  197. if (juce_canWriteToFile (source)
  198. && juce_copyFile (source, dest))
  199. {
  200. if (juce_deleteFile (source))
  201. return true;
  202. juce_deleteFile (dest);
  203. }
  204. return false;
  205. }
  206. void juce_createDirectory (const String& fileName) throw()
  207. {
  208. mkdir (fileName.toUTF8(), 0777);
  209. }
  210. void* juce_fileOpen (const String& fileName, bool forWriting) throw()
  211. {
  212. const char* const fileNameUTF8 = fileName.toUTF8();
  213. int flags = O_RDONLY;
  214. if (forWriting)
  215. {
  216. if (juce_fileExists (fileName, false))
  217. {
  218. const int f = open (fileNameUTF8, O_RDWR, 00644);
  219. if (f != -1)
  220. lseek (f, 0, SEEK_END);
  221. return (void*) f;
  222. }
  223. else
  224. {
  225. flags = O_RDWR + O_CREAT;
  226. }
  227. }
  228. return (void*) open (fileNameUTF8, flags, 00644);
  229. }
  230. void juce_fileClose (void* handle) throw()
  231. {
  232. if (handle != 0)
  233. close ((int) (pointer_sized_int) handle);
  234. }
  235. int juce_fileRead (void* handle, void* buffer, int size) throw()
  236. {
  237. if (handle != 0)
  238. return read ((int) (pointer_sized_int) handle, buffer, size);
  239. return 0;
  240. }
  241. int juce_fileWrite (void* handle, const void* buffer, int size) throw()
  242. {
  243. if (handle != 0)
  244. return write ((int) (pointer_sized_int) handle, buffer, size);
  245. return 0;
  246. }
  247. int64 juce_fileSetPosition (void* handle, int64 pos) throw()
  248. {
  249. if (handle != 0 && lseek ((int) (pointer_sized_int) handle, pos, SEEK_SET) == pos)
  250. return pos;
  251. return -1;
  252. }
  253. int64 juce_fileGetPosition (void* handle) throw()
  254. {
  255. if (handle != 0)
  256. return lseek ((int) (pointer_sized_int) handle, 0, SEEK_CUR);
  257. else
  258. return -1;
  259. }
  260. void juce_fileFlush (void* handle) throw()
  261. {
  262. if (handle != 0)
  263. fsync ((int) (pointer_sized_int) handle);
  264. }
  265. //==============================================================================
  266. // if this file doesn't exist, find a parent of it that does..
  267. static bool doStatFS (const File* file, struct statfs& result) throw()
  268. {
  269. File f (*file);
  270. for (int i = 5; --i >= 0;)
  271. {
  272. if (f.exists())
  273. break;
  274. f = f.getParentDirectory();
  275. }
  276. return statfs (f.getFullPathName().toUTF8(), &result) == 0;
  277. }
  278. int64 File::getBytesFreeOnVolume() const throw()
  279. {
  280. int64 free_space = 0;
  281. struct statfs buf;
  282. if (doStatFS (this, buf))
  283. // Note: this returns space available to non-super user
  284. free_space = (int64) buf.f_bsize * (int64) buf.f_bavail;
  285. return free_space;
  286. }
  287. const String juce_getVolumeLabel (const String& filenameOnVolume,
  288. int& volumeSerialNumber) throw()
  289. {
  290. // There is no equivalent on Linux
  291. volumeSerialNumber = 0;
  292. return String::empty;
  293. }
  294. //==============================================================================
  295. #if JUCE_64BIT
  296. #define filedesc ((long long) internal)
  297. #else
  298. #define filedesc ((int) internal)
  299. #endif
  300. InterProcessLock::InterProcessLock (const String& name_) throw()
  301. : internal (0),
  302. name (name_),
  303. reentrancyLevel (0)
  304. {
  305. #if JUCE_MAC
  306. // (don't use getSpecialLocation() to avoid the temp folder being different for each app)
  307. const File temp (File (T("~/Library/Caches/Juce")).getChildFile (name));
  308. #else
  309. const File temp (File::getSpecialLocation (File::tempDirectory).getChildFile (name));
  310. #endif
  311. temp.create();
  312. internal = (void*) open (temp.getFullPathName().toUTF8(), O_RDWR);
  313. }
  314. InterProcessLock::~InterProcessLock() throw()
  315. {
  316. while (reentrancyLevel > 0)
  317. this->exit();
  318. close (filedesc);
  319. }
  320. bool InterProcessLock::enter (const int timeOutMillisecs) throw()
  321. {
  322. if (internal == 0)
  323. return false;
  324. if (reentrancyLevel != 0)
  325. return true;
  326. const int64 endTime = Time::currentTimeMillis() + timeOutMillisecs;
  327. struct flock fl;
  328. zerostruct (fl);
  329. fl.l_whence = SEEK_SET;
  330. fl.l_type = F_WRLCK;
  331. for (;;)
  332. {
  333. const int result = fcntl (filedesc, F_SETLK, &fl);
  334. if (result >= 0)
  335. {
  336. ++reentrancyLevel;
  337. return true;
  338. }
  339. if (errno != EINTR)
  340. {
  341. if (timeOutMillisecs == 0
  342. || (timeOutMillisecs > 0 && Time::currentTimeMillis() >= endTime))
  343. break;
  344. Thread::sleep (10);
  345. }
  346. }
  347. return false;
  348. }
  349. void InterProcessLock::exit() throw()
  350. {
  351. if (reentrancyLevel > 0 && internal != 0)
  352. {
  353. --reentrancyLevel;
  354. struct flock fl;
  355. zerostruct (fl);
  356. fl.l_whence = SEEK_SET;
  357. fl.l_type = F_UNLCK;
  358. for (;;)
  359. {
  360. const int result = fcntl (filedesc, F_SETLKW, &fl);
  361. if (result >= 0 || errno != EINTR)
  362. break;
  363. }
  364. }
  365. }