openshot-audio  0.1.4
juce_posix_SharedCode.h
Go to the documentation of this file.
1 /*
2  ==============================================================================
3 
4  This file is part of the juce_core module of the JUCE library.
5  Copyright (c) 2015 - ROLI Ltd.
6 
7  Permission to use, copy, modify, and/or distribute this software for any purpose with
8  or without fee is hereby granted, provided that the above copyright notice and this
9  permission notice appear in all copies.
10 
11  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
12  TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
13  NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
15  IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16  CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 
18  ------------------------------------------------------------------------------
19 
20  NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
21  All other JUCE modules are covered by a dual GPL/commercial license, so if you are
22  using any other modules, be sure to check that you also comply with their license.
23 
24  For more details, visit www.juce.com
25 
26  ==============================================================================
27 */
28 
30 {
31  pthread_mutexattr_t atts;
32  pthread_mutexattr_init (&atts);
33  pthread_mutexattr_settype (&atts, PTHREAD_MUTEX_RECURSIVE);
34  #if ! JUCE_ANDROID
35  pthread_mutexattr_setprotocol (&atts, PTHREAD_PRIO_INHERIT);
36  #endif
37  pthread_mutex_init (&lock, &atts);
38  pthread_mutexattr_destroy (&atts);
39 }
40 
41 CriticalSection::~CriticalSection() noexcept { pthread_mutex_destroy (&lock); }
42 void CriticalSection::enter() const noexcept { pthread_mutex_lock (&lock); }
43 bool CriticalSection::tryEnter() const noexcept { return pthread_mutex_trylock (&lock) == 0; }
44 void CriticalSection::exit() const noexcept { pthread_mutex_unlock (&lock); }
45 
46 //==============================================================================
47 WaitableEvent::WaitableEvent (const bool useManualReset) noexcept
48  : triggered (false), manualReset (useManualReset)
49 {
50  pthread_cond_init (&condition, 0);
51 
52  pthread_mutexattr_t atts;
53  pthread_mutexattr_init (&atts);
54  #if ! JUCE_ANDROID
55  pthread_mutexattr_setprotocol (&atts, PTHREAD_PRIO_INHERIT);
56  #endif
57  pthread_mutex_init (&mutex, &atts);
58 }
59 
61 {
62  pthread_cond_destroy (&condition);
63  pthread_mutex_destroy (&mutex);
64 }
65 
66 bool WaitableEvent::wait (const int timeOutMillisecs) const noexcept
67 {
68  pthread_mutex_lock (&mutex);
69 
70  if (! triggered)
71  {
72  if (timeOutMillisecs < 0)
73  {
74  do
75  {
76  pthread_cond_wait (&condition, &mutex);
77  }
78  while (! triggered);
79  }
80  else
81  {
82  struct timeval now;
83  gettimeofday (&now, 0);
84 
85  struct timespec time;
86  time.tv_sec = now.tv_sec + (timeOutMillisecs / 1000);
87  time.tv_nsec = (now.tv_usec + ((timeOutMillisecs % 1000) * 1000)) * 1000;
88 
89  if (time.tv_nsec >= 1000000000)
90  {
91  time.tv_nsec -= 1000000000;
92  time.tv_sec++;
93  }
94 
95  do
96  {
97  if (pthread_cond_timedwait (&condition, &mutex, &time) == ETIMEDOUT)
98  {
99  pthread_mutex_unlock (&mutex);
100  return false;
101  }
102  }
103  while (! triggered);
104  }
105  }
106 
107  if (! manualReset)
108  triggered = false;
109 
110  pthread_mutex_unlock (&mutex);
111  return true;
112 }
113 
115 {
116  pthread_mutex_lock (&mutex);
117 
118  if (! triggered)
119  {
120  triggered = true;
121  pthread_cond_broadcast (&condition);
122  }
123 
124  pthread_mutex_unlock (&mutex);
125 }
126 
128 {
129  pthread_mutex_lock (&mutex);
130  triggered = false;
131  pthread_mutex_unlock (&mutex);
132 }
133 
134 //==============================================================================
135 void JUCE_CALLTYPE Thread::sleep (int millisecs)
136 {
137  struct timespec time;
138  time.tv_sec = millisecs / 1000;
139  time.tv_nsec = (millisecs % 1000) * 1000000;
140  nanosleep (&time, nullptr);
141 }
142 
144 {
145  #if JUCE_ANDROID
146  _exit (EXIT_FAILURE);
147  #else
148  std::_Exit (EXIT_FAILURE);
149  #endif
150 }
151 
152 //==============================================================================
153 const juce_wchar File::separator = '/';
154 const String File::separatorString ("/");
155 
156 //==============================================================================
158 {
159  HeapBlock<char> heapBuffer;
160 
161  char localBuffer [1024];
162  char* cwd = getcwd (localBuffer, sizeof (localBuffer) - 1);
163  size_t bufferSize = 4096;
164 
165  while (cwd == nullptr && errno == ERANGE)
166  {
167  heapBuffer.malloc (bufferSize);
168  cwd = getcwd (heapBuffer, bufferSize - 1);
169  bufferSize += 1024;
170  }
171 
172  return File (CharPointer_UTF8 (cwd));
173 }
174 
176 {
177  return chdir (getFullPathName().toUTF8()) == 0;
178 }
179 
180 //==============================================================================
181 // The unix siginterrupt function is deprecated - this does the same job.
182 int juce_siginterrupt (int sig, int flag)
183 {
184  struct ::sigaction act;
185  (void) ::sigaction (sig, nullptr, &act);
186 
187  if (flag != 0)
188  act.sa_flags &= ~SA_RESTART;
189  else
190  act.sa_flags |= SA_RESTART;
191 
192  return ::sigaction (sig, &act, nullptr);
193 }
194 
195 //==============================================================================
196 namespace
197 {
198  #if JUCE_LINUX || (JUCE_IOS && ! __DARWIN_ONLY_64_BIT_INO_T) // (this iOS stuff is to avoid a simulator bug)
199  typedef struct stat64 juce_statStruct;
200  #define JUCE_STAT stat64
201  #else
202  typedef struct stat juce_statStruct;
203  #define JUCE_STAT stat
204  #endif
205 
206  bool juce_stat (const String& fileName, juce_statStruct& info)
207  {
208  return fileName.isNotEmpty()
209  && JUCE_STAT (fileName.toUTF8(), &info) == 0;
210  }
211 
212  // if this file doesn't exist, find a parent of it that does..
213  bool juce_doStatFS (File f, struct statfs& result)
214  {
215  for (int i = 5; --i >= 0;)
216  {
217  if (f.exists())
218  break;
219 
220  f = f.getParentDirectory();
221  }
222 
223  return statfs (f.getFullPathName().toUTF8(), &result) == 0;
224  }
225 
226  #if (JUCE_MAC && MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || JUCE_IOS
227  static int64 getCreationTime (const juce_statStruct& s) noexcept { return (int64) s.st_birthtime; }
228  #else
229  static int64 getCreationTime (const juce_statStruct& s) noexcept { return (int64) s.st_ctime; }
230  #endif
231 
232  void updateStatInfoForFile (const String& path, bool* const isDir, int64* const fileSize,
233  Time* const modTime, Time* const creationTime, bool* const isReadOnly)
234  {
235  if (isDir != nullptr || fileSize != nullptr || modTime != nullptr || creationTime != nullptr)
236  {
237  juce_statStruct info;
238  const bool statOk = juce_stat (path, info);
239 
240  if (isDir != nullptr) *isDir = statOk && ((info.st_mode & S_IFDIR) != 0);
241  if (fileSize != nullptr) *fileSize = statOk ? (int64) info.st_size : 0;
242  if (modTime != nullptr) *modTime = Time (statOk ? (int64) info.st_mtime * 1000 : 0);
243  if (creationTime != nullptr) *creationTime = Time (statOk ? getCreationTime (info) * 1000 : 0);
244  }
245 
246  if (isReadOnly != nullptr)
247  *isReadOnly = access (path.toUTF8(), W_OK) != 0;
248  }
249 
250  Result getResultForErrno()
251  {
252  return Result::fail (String (strerror (errno)));
253  }
254 
255  Result getResultForReturnValue (int value)
256  {
257  return value == -1 ? getResultForErrno() : Result::ok();
258  }
259 
260  int getFD (void* handle) noexcept { return (int) (pointer_sized_int) handle; }
261  void* fdToVoidPointer (int fd) noexcept { return (void*) (pointer_sized_int) fd; }
262 }
263 
264 bool File::isDirectory() const
265 {
266  juce_statStruct info;
267 
268  return fullPath.isNotEmpty()
269  && (juce_stat (fullPath, info) && ((info.st_mode & S_IFDIR) != 0));
270 }
271 
272 bool File::exists() const
273 {
274  return fullPath.isNotEmpty()
275  && access (fullPath.toUTF8(), F_OK) == 0;
276 }
277 
278 bool File::existsAsFile() const
279 {
280  return exists() && ! isDirectory();
281 }
282 
284 {
285  juce_statStruct info;
286  return juce_stat (fullPath, info) ? info.st_size : 0;
287 }
288 
290 {
291  juce_statStruct info;
292  return juce_stat (fullPath, info) ? (uint64) info.st_ino : 0;
293 }
294 
295 //==============================================================================
297 {
298  if (exists())
299  return access (fullPath.toUTF8(), W_OK) == 0;
300 
301  if ((! isDirectory()) && fullPath.containsChar (separator))
302  return getParentDirectory().hasWriteAccess();
303 
304  return false;
305 }
306 
307 static bool setFileModeFlags (const String& fullPath, mode_t flags, bool shouldSet) noexcept
308 {
309  juce_statStruct info;
310  if (! juce_stat (fullPath, info))
311  return false;
312 
313  info.st_mode &= 0777;
314 
315  if (shouldSet)
316  info.st_mode |= flags;
317  else
318  info.st_mode &= ~flags;
319 
320  return chmod (fullPath.toUTF8(), info.st_mode) == 0;
321 }
322 
323 bool File::setFileReadOnlyInternal (bool shouldBeReadOnly) const
324 {
325  // Hmm.. should we give global write permission or just the current user?
326  return setFileModeFlags (fullPath, S_IWUSR | S_IWGRP | S_IWOTH, ! shouldBeReadOnly);
327 }
328 
329 bool File::setFileExecutableInternal (bool shouldBeExecutable) const
330 {
331  return setFileModeFlags (fullPath, S_IXUSR | S_IXGRP | S_IXOTH, shouldBeExecutable);
332 }
333 
334 void File::getFileTimesInternal (int64& modificationTime, int64& accessTime, int64& creationTime) const
335 {
336  modificationTime = 0;
337  accessTime = 0;
338  creationTime = 0;
339 
340  juce_statStruct info;
341 
342  if (juce_stat (fullPath, info))
343  {
344  modificationTime = (int64) info.st_mtime * 1000;
345  accessTime = (int64) info.st_atime * 1000;
346  creationTime = (int64) info.st_ctime * 1000;
347  }
348 }
349 
350 bool File::setFileTimesInternal (int64 modificationTime, int64 accessTime, int64 /*creationTime*/) const
351 {
352  juce_statStruct info;
353 
354  if ((modificationTime != 0 || accessTime != 0) && juce_stat (fullPath, info))
355  {
356  struct utimbuf times;
357  times.actime = accessTime != 0 ? (time_t) (accessTime / 1000) : info.st_atime;
358  times.modtime = modificationTime != 0 ? (time_t) (modificationTime / 1000) : info.st_mtime;
359 
360  return utime (fullPath.toUTF8(), &times) == 0;
361  }
362 
363  return false;
364 }
365 
366 bool File::deleteFile() const
367 {
368  if (! exists())
369  return true;
370 
371  if (isDirectory())
372  return rmdir (fullPath.toUTF8()) == 0;
373 
374  return remove (fullPath.toUTF8()) == 0;
375 }
376 
377 bool File::moveInternal (const File& dest) const
378 {
379  if (rename (fullPath.toUTF8(), dest.getFullPathName().toUTF8()) == 0)
380  return true;
381 
382  if (hasWriteAccess() && copyInternal (dest))
383  {
384  if (deleteFile())
385  return true;
386 
387  dest.deleteFile();
388  }
389 
390  return false;
391 }
392 
393 Result File::createDirectoryInternal (const String& fileName) const
394 {
395  return getResultForReturnValue (mkdir (fileName.toUTF8(), 0777));
396 }
397 
398 //=====================================================================
399 int64 juce_fileSetPosition (void* handle, int64 pos)
400 {
401  if (handle != 0 && lseek (getFD (handle), pos, SEEK_SET) == pos)
402  return pos;
403 
404  return -1;
405 }
406 
407 void FileInputStream::openHandle()
408 {
409  const int f = open (file.getFullPathName().toUTF8(), O_RDONLY, 00644);
410 
411  if (f != -1)
412  fileHandle = fdToVoidPointer (f);
413  else
414  status = getResultForErrno();
415 }
416 
418 {
419  if (fileHandle != 0)
420  close (getFD (fileHandle));
421 }
422 
423 size_t FileInputStream::readInternal (void* const buffer, const size_t numBytes)
424 {
425  ssize_t result = 0;
426 
427  if (fileHandle != 0)
428  {
429  result = ::read (getFD (fileHandle), buffer, numBytes);
430 
431  if (result < 0)
432  {
433  status = getResultForErrno();
434  result = 0;
435  }
436  }
437 
438  return (size_t) result;
439 }
440 
441 //==============================================================================
442 void FileOutputStream::openHandle()
443 {
444  if (file.exists())
445  {
446  const int f = open (file.getFullPathName().toUTF8(), O_RDWR, 00644);
447 
448  if (f != -1)
449  {
450  currentPosition = lseek (f, 0, SEEK_END);
451 
452  if (currentPosition >= 0)
453  {
454  fileHandle = fdToVoidPointer (f);
455  }
456  else
457  {
458  status = getResultForErrno();
459  close (f);
460  }
461  }
462  else
463  {
464  status = getResultForErrno();
465  }
466  }
467  else
468  {
469  const int f = open (file.getFullPathName().toUTF8(), O_RDWR + O_CREAT, 00644);
470 
471  if (f != -1)
472  fileHandle = fdToVoidPointer (f);
473  else
474  status = getResultForErrno();
475  }
476 }
477 
478 void FileOutputStream::closeHandle()
479 {
480  if (fileHandle != 0)
481  {
482  close (getFD (fileHandle));
483  fileHandle = 0;
484  }
485 }
486 
487 ssize_t FileOutputStream::writeInternal (const void* const data, const size_t numBytes)
488 {
489  ssize_t result = 0;
490 
491  if (fileHandle != 0)
492  {
493  result = ::write (getFD (fileHandle), data, numBytes);
494 
495  if (result == -1)
496  status = getResultForErrno();
497  }
498 
499  return result;
500 }
501 
502 void FileOutputStream::flushInternal()
503 {
504  if (fileHandle != 0)
505  {
506  if (fsync (getFD (fileHandle)) == -1)
507  status = getResultForErrno();
508 
509  #if JUCE_ANDROID
510  // This stuff tells the OS to asynchronously update the metadata
511  // that the OS has cached aboud the file - this metadata is used
512  // when the device is acting as a USB drive, and unless it's explicitly
513  // refreshed, it'll get out of step with the real file.
514  const LocalRef<jstring> t (javaString (file.getFullPathName()));
515  android.activity.callVoidMethod (JuceAppActivity.scanFile, t.get());
516  #endif
517  }
518 }
519 
521 {
522  if (fileHandle == 0)
523  return status;
524 
525  flush();
526  return getResultForReturnValue (ftruncate (getFD (fileHandle), (off_t) currentPosition));
527 }
528 
529 //==============================================================================
530 String SystemStats::getEnvironmentVariable (const String& name, const String& defaultValue)
531 {
532  if (const char* s = ::getenv (name.toUTF8()))
533  return String::fromUTF8 (s);
534 
535  return defaultValue;
536 }
537 
538 //==============================================================================
539 void MemoryMappedFile::openInternal (const File& file, AccessMode mode)
540 {
541  jassert (mode == readOnly || mode == readWrite);
542 
543  if (range.getStart() > 0)
544  {
545  const long pageSize = sysconf (_SC_PAGE_SIZE);
546  range.setStart (range.getStart() - (range.getStart() % pageSize));
547  }
548 
549  fileHandle = open (file.getFullPathName().toUTF8(),
550  mode == readWrite ? (O_CREAT + O_RDWR) : O_RDONLY, 00644);
551 
552  if (fileHandle != -1)
553  {
554  void* m = mmap (0, (size_t) range.getLength(),
555  mode == readWrite ? (PROT_READ | PROT_WRITE) : PROT_READ,
556  MAP_SHARED, fileHandle,
557  (off_t) range.getStart());
558 
559  if (m != MAP_FAILED)
560  {
561  address = m;
562  madvise (m, (size_t) range.getLength(), MADV_SEQUENTIAL);
563  }
564  else
565  {
566  range = Range<int64>();
567  }
568  }
569 }
570 
572 {
573  if (address != nullptr)
574  munmap (address, (size_t) range.getLength());
575 
576  if (fileHandle != 0)
577  close (fileHandle);
578 }
579 
580 //==============================================================================
581 #if JUCE_PROJUCER_LIVE_BUILD
582 extern "C" const char* juce_getCurrentExecutablePath();
583 #endif
584 
587 {
588  #if JUCE_PROJUCER_LIVE_BUILD
589  return File (juce_getCurrentExecutablePath());
590  #elif JUCE_ANDROID
591  return File (android.appFile);
592  #else
593  struct DLAddrReader
594  {
595  static String getFilename()
596  {
597  Dl_info exeInfo;
598  dladdr ((void*) juce_getExecutableFile, &exeInfo);
599  return CharPointer_UTF8 (exeInfo.dli_fname);
600  }
601  };
602 
603  static String filename (DLAddrReader::getFilename());
605  #endif
606 }
607 
608 //==============================================================================
610 {
611  struct statfs buf;
612  if (juce_doStatFS (*this, buf))
613  return (int64) buf.f_bsize * (int64) buf.f_bavail; // Note: this returns space available to non-super user
614 
615  return 0;
616 }
617 
619 {
620  struct statfs buf;
621  if (juce_doStatFS (*this, buf))
622  return (int64) buf.f_bsize * (int64) buf.f_blocks;
623 
624  return 0;
625 }
626 
628 {
629  #if JUCE_MAC
630  struct VolAttrBuf
631  {
632  u_int32_t length;
633  attrreference_t mountPointRef;
634  char mountPointSpace [MAXPATHLEN];
635  } attrBuf;
636 
637  struct attrlist attrList;
638  zerostruct (attrList); // (can't use "= { 0 }" on this object because it's typedef'ed as a C struct)
639  attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
640  attrList.volattr = ATTR_VOL_INFO | ATTR_VOL_NAME;
641 
642  File f (*this);
643 
644  for (;;)
645  {
646  if (getattrlist (f.getFullPathName().toUTF8(), &attrList, &attrBuf, sizeof (attrBuf), 0) == 0)
647  return String::fromUTF8 (((const char*) &attrBuf.mountPointRef) + attrBuf.mountPointRef.attr_dataoffset,
648  (int) attrBuf.mountPointRef.attr_length);
649 
650  const File parent (f.getParentDirectory());
651 
652  if (f == parent)
653  break;
654 
655  f = parent;
656  }
657  #endif
658 
659  return String();
660 }
661 
663 {
664  int result = 0;
665 /* int fd = open (getFullPathName().toUTF8(), O_RDONLY | O_NONBLOCK);
666 
667  char info [512];
668 
669  #ifndef HDIO_GET_IDENTITY
670  #define HDIO_GET_IDENTITY 0x030d
671  #endif
672 
673  if (ioctl (fd, HDIO_GET_IDENTITY, info) == 0)
674  {
675  DBG (String (info + 20, 20));
676  result = String (info + 20, 20).trim().getIntValue();
677  }
678 
679  close (fd);*/
680  return result;
681 }
682 
683 //==============================================================================
684 #if ! JUCE_IOS
685 void juce_runSystemCommand (const String&);
686 void juce_runSystemCommand (const String& command)
687 {
688  int result = system (command.toUTF8());
689  (void) result;
690 }
691 
694 {
695  // slight bodge here, as we just pipe the output into a temp file and read it...
697  .getNonexistentChildFile (String::toHexString (Random::getSystemRandom().nextInt()), ".tmp", false));
698 
699  juce_runSystemCommand (command + " > " + tempFile.getFullPathName());
700 
701  String result (tempFile.loadFileAsString());
702  tempFile.deleteFile();
703  return result;
704 }
705 #endif
706 
707 //==============================================================================
708 #if JUCE_IOS
710 {
711 public:
712  Pimpl (const String&, int)
713  : handle (1), refCount (1) // On iOS just fake success..
714  {
715  }
716 
717  int handle, refCount;
718 };
719 
720 #else
721 
723 {
724 public:
725  Pimpl (const String& lockName, const int timeOutMillisecs)
726  : handle (0), refCount (1)
727  {
728  #if JUCE_MAC
729  if (! createLockFile (File ("~/Library/Caches/com.juce.locks").getChildFile (lockName), timeOutMillisecs))
730  // Fallback if the user's home folder is on a network drive with no ability to lock..
731  createLockFile (File ("/tmp/com.juce.locks").getChildFile (lockName), timeOutMillisecs);
732 
733  #else
734  File tempFolder ("/var/tmp");
735  if (! tempFolder.isDirectory())
736  tempFolder = "/tmp";
737 
738  createLockFile (tempFolder.getChildFile (lockName), timeOutMillisecs);
739  #endif
740  }
741 
743  {
744  closeFile();
745  }
746 
747  bool createLockFile (const File& file, const int timeOutMillisecs)
748  {
749  file.create();
750  handle = open (file.getFullPathName().toUTF8(), O_RDWR);
751 
752  if (handle != 0)
753  {
754  struct flock fl;
755  zerostruct (fl);
756 
757  fl.l_whence = SEEK_SET;
758  fl.l_type = F_WRLCK;
759 
760  const int64 endTime = Time::currentTimeMillis() + timeOutMillisecs;
761 
762  for (;;)
763  {
764  const int result = fcntl (handle, F_SETLK, &fl);
765 
766  if (result >= 0)
767  return true;
768 
769  const int error = errno;
770 
771  if (error != EINTR)
772  {
773  if (error == EBADF || error == ENOTSUP)
774  return false;
775 
776  if (timeOutMillisecs == 0
777  || (timeOutMillisecs > 0 && Time::currentTimeMillis() >= endTime))
778  break;
779 
780  Thread::sleep (10);
781  }
782  }
783  }
784 
785  closeFile();
786  return true; // only false if there's a file system error. Failure to lock still returns true.
787  }
788 
789  void closeFile()
790  {
791  if (handle != 0)
792  {
793  struct flock fl;
794  zerostruct (fl);
795 
796  fl.l_whence = SEEK_SET;
797  fl.l_type = F_UNLCK;
798 
799  while (! (fcntl (handle, F_SETLKW, &fl) >= 0 || errno != EINTR))
800  {}
801 
802  close (handle);
803  handle = 0;
804  }
805  }
806 
807  int handle, refCount;
808 };
809 #endif
810 
812 {
813 }
814 
816 {
817 }
818 
819 bool InterProcessLock::enter (const int timeOutMillisecs)
820 {
821  const ScopedLock sl (lock);
822 
823  if (pimpl == nullptr)
824  {
825  pimpl = new Pimpl (name, timeOutMillisecs);
826 
827  if (pimpl->handle == 0)
828  pimpl = nullptr;
829  }
830  else
831  {
832  pimpl->refCount++;
833  }
834 
835  return pimpl != nullptr;
836 }
837 
839 {
840  const ScopedLock sl (lock);
841 
842  // Trying to release the lock too many times!
843  jassert (pimpl != nullptr);
844 
845  if (pimpl != nullptr && --(pimpl->refCount) == 0)
846  pimpl = nullptr;
847 }
848 
849 //==============================================================================
850 void JUCE_API juce_threadEntryPoint (void*);
851 
852 extern "C" void* threadEntryProc (void*);
853 extern "C" void* threadEntryProc (void* userData)
854 {
856  {
857  #if JUCE_ANDROID
858  const AndroidThreadScope androidEnv;
859  #endif
860 
861  juce_threadEntryPoint (userData);
862  }
863 
864  return nullptr;
865 }
866 
867 void Thread::launchThread()
868 {
869  threadHandle = 0;
870  pthread_t handle = 0;
871 
872  if (pthread_create (&handle, 0, threadEntryProc, this) == 0)
873  {
874  pthread_detach (handle);
875  threadHandle = (void*) handle;
876  threadId = (ThreadID) threadHandle;
877  }
878 }
879 
880 void Thread::closeThreadHandle()
881 {
882  threadId = 0;
883  threadHandle = 0;
884 }
885 
886 void Thread::killThread()
887 {
888  if (threadHandle != 0)
889  {
890  #if JUCE_ANDROID
891  jassertfalse; // pthread_cancel not available!
892  #else
893  pthread_cancel ((pthread_t) threadHandle);
894  #endif
895  }
896 }
897 
899 {
900  #if JUCE_IOS || (JUCE_MAC && defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
902  {
903  [[NSThread currentThread] setName: juceStringToNS (name)];
904  }
905  #elif JUCE_LINUX
906  pthread_setname_np (pthread_self(), name.toRawUTF8());
907  #endif
908 }
909 
910 bool Thread::setThreadPriority (void* handle, int priority)
911 {
912  struct sched_param param;
913  int policy;
914  priority = jlimit (0, 10, priority);
915 
916  if (handle == nullptr)
917  handle = (void*) pthread_self();
918 
919  if (pthread_getschedparam ((pthread_t) handle, &policy, &param) != 0)
920  return false;
921 
922  policy = priority == 0 ? SCHED_OTHER : SCHED_RR;
923 
924  const int minPriority = sched_get_priority_min (policy);
925  const int maxPriority = sched_get_priority_max (policy);
926 
927  param.sched_priority = ((maxPriority - minPriority) * priority) / 10 + minPriority;
928  return pthread_setschedparam ((pthread_t) handle, policy, &param) == 0;
929 }
930 
932 {
933  return (ThreadID) pthread_self();
934 }
935 
937 {
938  sched_yield();
939 }
940 
941 //==============================================================================
942 /* Remove this macro if you're having problems compiling the cpu affinity
943  calls (the API for these has changed about quite a bit in various Linux
944  versions, and a lot of distros seem to ship with obsolete versions)
945 */
946 #if defined (CPU_ISSET) && ! defined (SUPPORT_AFFINITIES)
947  #define SUPPORT_AFFINITIES 1
948 #endif
949 
951 {
952  #if SUPPORT_AFFINITIES
953  cpu_set_t affinity;
954  CPU_ZERO (&affinity);
955 
956  for (int i = 0; i < 32; ++i)
957  if ((affinityMask & (1 << i)) != 0)
958  CPU_SET (i, &affinity);
959 
960  #if (! JUCE_ANDROID) && ((! JUCE_LINUX) || ((__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2004))
961  pthread_setaffinity_np (pthread_self(), sizeof (cpu_set_t), &affinity);
962  #else
963  // NB: this call isn't really correct because it sets the affinity of the process,
964  // not the thread. But it's included here as a fallback for people who are using
965  // ridiculously old versions of glibc
966  sched_setaffinity (getpid(), sizeof (cpu_set_t), &affinity);
967  #endif
968 
969  sched_yield();
970 
971  #else
972  // affinities aren't supported because either the appropriate header files weren't found,
973  // or the SUPPORT_AFFINITIES macro was turned off
974  jassertfalse;
975  ignoreUnused (affinityMask);
976  #endif
977 }
978 
979 //==============================================================================
980 bool DynamicLibrary::open (const String& name)
981 {
982  close();
983  handle = dlopen (name.isEmpty() ? nullptr : name.toUTF8().getAddress(), RTLD_LOCAL | RTLD_NOW);
984  return handle != nullptr;
985 }
986 
988 {
989  if (handle != nullptr)
990  {
991  dlclose (handle);
992  handle = nullptr;
993  }
994 }
995 
996 void* DynamicLibrary::getFunction (const String& functionName) noexcept
997 {
998  return handle != nullptr ? dlsym (handle, functionName.toUTF8()) : nullptr;
999 }
1000 
1001 
1002 
1003 //==============================================================================
1005 {
1006 public:
1007  ActiveProcess (const StringArray& arguments, int streamFlags)
1008  : childPID (0), pipeHandle (0), readHandle (0)
1009  {
1010  // Looks like you're trying to launch a non-existent exe or a folder (perhaps on OSX
1011  // you're trying to launch the .app folder rather than the actual binary inside it?)
1012  jassert ((! arguments[0].containsChar ('/'))
1013  || File::getCurrentWorkingDirectory().getChildFile (arguments[0]).existsAsFile());
1014 
1015  int pipeHandles[2] = { 0 };
1016 
1017  if (pipe (pipeHandles) == 0)
1018  {
1019  const pid_t result = fork();
1020 
1021  if (result < 0)
1022  {
1023  close (pipeHandles[0]);
1024  close (pipeHandles[1]);
1025  }
1026  else if (result == 0)
1027  {
1028  // we're the child process..
1029  close (pipeHandles[0]); // close the read handle
1030 
1031  if ((streamFlags & wantStdOut) != 0)
1032  dup2 (pipeHandles[1], 1); // turns the pipe into stdout
1033  else
1034  close (STDOUT_FILENO);
1035 
1036  if ((streamFlags & wantStdErr) != 0)
1037  dup2 (pipeHandles[1], 2);
1038  else
1039  close (STDERR_FILENO);
1040 
1041  close (pipeHandles[1]);
1042 
1043  Array<char*> argv;
1044  for (int i = 0; i < arguments.size(); ++i)
1045  if (arguments[i].isNotEmpty())
1046  argv.add (const_cast<char*> (arguments[i].toUTF8().getAddress()));
1047 
1048  argv.add (nullptr);
1049 
1050  execvp (argv[0], argv.getRawDataPointer());
1051  exit (-1);
1052  }
1053  else
1054  {
1055  // we're the parent process..
1056  childPID = result;
1057  pipeHandle = pipeHandles[0];
1058  close (pipeHandles[1]); // close the write handle
1059  }
1060  }
1061  }
1062 
1064  {
1065  if (readHandle != 0)
1066  fclose (readHandle);
1067 
1068  if (pipeHandle != 0)
1069  close (pipeHandle);
1070  }
1071 
1072  bool isRunning() const noexcept
1073  {
1074  if (childPID != 0)
1075  {
1076  int childState;
1077  const int pid = waitpid (childPID, &childState, WNOHANG);
1078  return pid == 0 || ! (WIFEXITED (childState) || WIFSIGNALED (childState));
1079  }
1080 
1081  return false;
1082  }
1083 
1084  int read (void* const dest, const int numBytes) noexcept
1085  {
1086  jassert (dest != nullptr);
1087 
1088  #ifdef fdopen
1089  #error // the zlib headers define this function as NULL!
1090  #endif
1091 
1092  if (readHandle == 0 && childPID != 0)
1093  readHandle = fdopen (pipeHandle, "r");
1094 
1095  if (readHandle != 0)
1096  return (int) fread (dest, 1, (size_t) numBytes, readHandle);
1097 
1098  return 0;
1099  }
1100 
1101  bool killProcess() const noexcept
1102  {
1103  return ::kill (childPID, SIGKILL) == 0;
1104  }
1105 
1107  {
1108  if (childPID != 0)
1109  {
1110  int childState = 0;
1111  const int pid = waitpid (childPID, &childState, WNOHANG);
1112 
1113  if (pid >= 0 && WIFEXITED (childState))
1114  return WEXITSTATUS (childState);
1115  }
1116 
1117  return 0;
1118  }
1119 
1121 
1122 private:
1123  int pipeHandle;
1124  FILE* readHandle;
1125 
1127 };
1128 
1129 bool ChildProcess::start (const String& command, int streamFlags)
1130 {
1131  return start (StringArray::fromTokens (command, true), streamFlags);
1132 }
1133 
1134 bool ChildProcess::start (const StringArray& args, int streamFlags)
1135 {
1136  if (args.size() == 0)
1137  return false;
1138 
1139  activeProcess = new ActiveProcess (args, streamFlags);
1140 
1141  if (activeProcess->childPID == 0)
1142  activeProcess = nullptr;
1143 
1144  return activeProcess != nullptr;
1145 }
1146 
1147 //==============================================================================
1149 {
1150  Pimpl (HighResolutionTimer& t) : owner (t), thread (0), shouldStop (false)
1151  {
1152  }
1153 
1155  {
1156  jassert (thread == 0);
1157  }
1158 
1159  void start (int newPeriod)
1160  {
1161  if (periodMs != newPeriod)
1162  {
1163  if (thread != pthread_self())
1164  {
1165  stop();
1166 
1167  periodMs = newPeriod;
1168  shouldStop = false;
1169 
1170  if (pthread_create (&thread, nullptr, timerThread, this) == 0)
1171  setThreadToRealtime (thread, (uint64) newPeriod);
1172  else
1173  jassertfalse;
1174  }
1175  else
1176  {
1177  periodMs = newPeriod;
1178  shouldStop = false;
1179  }
1180  }
1181  }
1182 
1183  void stop()
1184  {
1185  if (thread != 0)
1186  {
1187  shouldStop = true;
1188 
1189  while (thread != 0 && thread != pthread_self())
1190  Thread::yield();
1191  }
1192  }
1193 
1195  int volatile periodMs;
1196 
1197 private:
1198  pthread_t thread;
1199  bool volatile shouldStop;
1200 
1201  static void* timerThread (void* param)
1202  {
1203  #if JUCE_ANDROID
1204  const AndroidThreadScope androidEnv;
1205  #else
1206  int dummy;
1207  pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &dummy);
1208  #endif
1209 
1210  reinterpret_cast<Pimpl*> (param)->timerThread();
1211  return nullptr;
1212  }
1213 
1214  void timerThread()
1215  {
1216  int lastPeriod = periodMs;
1217  Clock clock (lastPeriod);
1218 
1219  while (! shouldStop)
1220  {
1221  clock.wait();
1222  owner.hiResTimerCallback();
1223 
1224  if (lastPeriod != periodMs)
1225  {
1226  lastPeriod = periodMs;
1227  clock = Clock (lastPeriod);
1228  }
1229  }
1230 
1231  periodMs = 0;
1232  thread = 0;
1233  }
1234 
1235  struct Clock
1236  {
1237  #if JUCE_MAC || JUCE_IOS
1238  Clock (double millis) noexcept
1239  {
1240  mach_timebase_info_data_t timebase;
1241  (void) mach_timebase_info (&timebase);
1242  delta = (((uint64_t) (millis * 1000000.0)) * timebase.denom) / timebase.numer;
1243  time = mach_absolute_time();
1244  }
1245 
1246  void wait() noexcept
1247  {
1248  time += delta;
1249  mach_wait_until (time);
1250  }
1251 
1252  uint64_t time, delta;
1253 
1254  #elif JUCE_ANDROID
1255  Clock (double millis) noexcept : delta ((uint64) (millis * 1000000))
1256  {
1257  }
1258 
1259  void wait() noexcept
1260  {
1261  struct timespec t;
1262  t.tv_sec = (time_t) (delta / 1000000000);
1263  t.tv_nsec = (long) (delta % 1000000000);
1264  nanosleep (&t, nullptr);
1265  }
1266 
1267  uint64 delta;
1268  #else
1269  Clock (double millis) noexcept : delta ((uint64) (millis * 1000000))
1270  {
1271  struct timespec t;
1272  clock_gettime (CLOCK_MONOTONIC, &t);
1273  time = (uint64) (1000000000 * (int64) t.tv_sec + (int64) t.tv_nsec);
1274  }
1275 
1276  void wait() noexcept
1277  {
1278  time += delta;
1279 
1280  struct timespec t;
1281  t.tv_sec = (time_t) (time / 1000000000);
1282  t.tv_nsec = (long) (time % 1000000000);
1283 
1284  clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &t, nullptr);
1285  }
1286 
1287  uint64 time, delta;
1288  #endif
1289  };
1290 
1291  static bool setThreadToRealtime (pthread_t thread, uint64 periodMs)
1292  {
1293  #if JUCE_MAC || JUCE_IOS
1294  thread_time_constraint_policy_data_t policy;
1295  policy.period = (uint32_t) (periodMs * 1000000);
1296  policy.computation = 50000;
1297  policy.constraint = policy.period;
1298  policy.preemptible = true;
1299 
1300  return thread_policy_set (pthread_mach_thread_np (thread),
1301  THREAD_TIME_CONSTRAINT_POLICY,
1302  (thread_policy_t) &policy,
1303  THREAD_TIME_CONSTRAINT_POLICY_COUNT) == KERN_SUCCESS;
1304 
1305  #else
1306  (void) periodMs;
1307  struct sched_param param;
1308  param.sched_priority = sched_get_priority_max (SCHED_RR);
1309  return pthread_setschedparam (thread, SCHED_RR, &param) == 0;
1310 
1311  #endif
1312  }
1313 
1315 };
void * ThreadID
Definition: juce_Thread.h:224
Result create() const
Definition: juce_File.cpp:429
void enter() const noexcept
Definition: juce_posix_SharedCode.h:42
static String toHexString(int number)
Definition: juce_String.cpp:1925
String getVolumeLabel() const
Definition: juce_posix_SharedCode.h:627
bool enter(int timeOutMillisecs=-1)
Definition: juce_posix_SharedCode.h:819
uint64 getFileIdentifier() const
Definition: juce_posix_SharedCode.h:289
int64 getBytesFreeOnVolume() const
Definition: juce_posix_SharedCode.h:609
bool open(const String &name)
Definition: juce_posix_SharedCode.h:980
~ActiveProcess()
Definition: juce_posix_SharedCode.h:1063
~WaitableEvent() noexcept
Definition: juce_posix_SharedCode.h:60
int pointer_sized_int
Definition: juce_MathsFunctions.h:86
Pimpl(const String &lockName, const int timeOutMillisecs)
Definition: juce_posix_SharedCode.h:725
~CriticalSection() noexcept
Definition: juce_posix_SharedCode.h:41
#define noexcept
Definition: juce_CompilerSupport.h:141
File juce_getExecutableFile()
Definition: juce_posix_SharedCode.h:586
void exit()
Definition: juce_posix_SharedCode.h:838
bool start(const String &command, int streamFlags=wantStdOut|wantStdErr)
Definition: juce_posix_SharedCode.h:1129
String appFile
Definition: juce_android_JNIHelpers.h:250
Definition: juce_ScopedLock.h:59
static String getEnvironmentVariable(const String &name, const String &defaultValue)
Definition: juce_posix_SharedCode.h:530
Definition: juce_Time.h:41
void malloc(const size_t newNumElements, const size_t elementSize=sizeof(ElementType))
Definition: juce_HeapBlock.h:220
Definition: juce_CharPointer_UTF8.h:38
~Pimpl()
Definition: juce_posix_SharedCode.h:1154
String juce_getOutputFromCommand(const String &)
Definition: juce_posix_SharedCode.h:693
static void JUCE_CALLTYPE setCurrentThreadAffinityMask(uint32 affinityMask)
Definition: juce_posix_SharedCode.h:950
static ThreadID JUCE_CALLTYPE getCurrentThreadId()
Definition: juce_posix_SharedCode.h:931
static File getCurrentWorkingDirectory()
Definition: juce_posix_SharedCode.h:157
int64 getVolumeTotalSize() const
Definition: juce_posix_SharedCode.h:618
void add(const ElementType &newElement)
Definition: juce_Array.h:392
int juce_siginterrupt(int sig, int flag)
Definition: juce_posix_SharedCode.h:182
#define JUCE_CALLTYPE
Definition: juce_PlatformDefs.h:50
static void JUCE_CALLTYPE yield()
Definition: juce_posix_SharedCode.h:936
#define jassertfalse
Definition: juce_PlatformDefs.h:141
void callVoidMethod(jmethodID methodID,...) const
Definition: juce_android_JNIHelpers.h:91
Definition: juce_String.h:43
File getParentDirectory() const
Definition: juce_File.cpp:304
Definition: juce_Result.h:61
void * threadEntryProc(void *)
Definition: juce_posix_SharedCode.h:853
static const String separatorString
Definition: juce_File.h:908
void signal() const noexcept
Definition: juce_posix_SharedCode.h:114
void juce_runSystemCommand(const String &)
Definition: juce_posix_SharedCode.h:686
void ignoreUnused(const Type1 &) noexcept
Definition: juce_core.h:280
#define JUCE_API
Definition: juce_StandardHeader.h:139
bool isNotEmpty() const noexcept
Definition: juce_String.h:308
AndroidSystem android
Definition: juce_android_SystemStats.cpp:158
virtual void hiResTimerCallback()=0
Definition: juce_HighResolutionTimer.h:46
int getVolumeSerialNumber() const
Definition: juce_posix_SharedCode.h:662
void start(int newPeriod)
Definition: juce_posix_SharedCode.h:1159
int64 getSize() const
Definition: juce_posix_SharedCode.h:283
void reset() const noexcept
Definition: juce_posix_SharedCode.h:127
void zerostruct(Type &structure) noexcept
Definition: juce_Memory.h:38
bool hasWriteAccess() const
Definition: juce_posix_SharedCode.h:296
JavaType get() const noexcept
Definition: juce_android_JNIHelpers.h:133
static StringArray fromTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
Definition: juce_StringArray.cpp:403
ActiveProcess(const StringArray &arguments, int streamFlags)
Definition: juce_posix_SharedCode.h:1007
int volatile periodMs
Definition: juce_posix_SharedCode.h:1195
unsigned long long uint64
Definition: juce_MathsFunctions.h:62
unsigned int uint32
Definition: juce_MathsFunctions.h:51
HighResolutionTimer & owner
Definition: juce_posix_SharedCode.h:1194
bool killProcess() const noexcept
Definition: juce_posix_SharedCode.h:1101
static int64 currentTimeMillis() noexcept
Definition: juce_Time.cpp:196
static void JUCE_CALLTYPE setCurrentThreadName(const String &newThreadName)
Definition: juce_posix_SharedCode.h:898
bool isRunning() const noexcept
Definition: juce_posix_SharedCode.h:1072
static void JUCE_CALLTYPE terminate()
Definition: juce_posix_SharedCode.h:143
static const juce_wchar separator
Definition: juce_File.h:903
#define JUCE_STAT
Definition: juce_posix_SharedCode.h:203
bool setAsCurrentWorkingDirectory() const
Definition: juce_posix_SharedCode.h:175
CharPointer_UTF8 toUTF8() const
Definition: juce_String.cpp:2057
bool isEmpty() const noexcept
Definition: juce_String.h:302
static Random & getSystemRandom() noexcept
Definition: juce_Random.cpp:64
bool deleteFile() const
Definition: juce_posix_SharedCode.h:366
bool isDirectory() const
Definition: juce_posix_SharedCode.h:264
CriticalSection() noexcept
Definition: juce_posix_SharedCode.h:29
long long int64
Definition: juce_MathsFunctions.h:60
int refCount
Definition: juce_posix_SharedCode.h:807
#define JUCE_AUTORELEASEPOOL
void JUCE_API juce_threadEntryPoint(void *)
Definition: juce_core.cpp:112
int size() const noexcept
Definition: juce_StringArray.h:121
bool exists() const
Definition: juce_posix_SharedCode.h:272
Definition: juce_StringArray.h:39
bool wait(int timeOutMilliseconds=-1) const noexcept
Definition: juce_posix_SharedCode.h:66
String loadFileAsString() const
Definition: juce_File.cpp:487
Type jlimit(const Type lowerLimit, const Type upperLimit, const Type valueToConstrain) noexcept
Definition: juce_MathsFunctions.h:220
static Result ok() noexcept
Definition: juce_Result.h:66
InterProcessLock(const String &name)
Definition: juce_posix_SharedCode.h:811
void * getFunction(const String &functionName) noexcept
Definition: juce_posix_SharedCode.h:996
Definition: juce_Array.h:60
#define jassert(a)
Definition: juce_PlatformDefs.h:146
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)
Definition: juce_String.cpp:2112
bool tryEnter() const noexcept
Definition: juce_posix_SharedCode.h:43
Definition: juce_android_JNIHelpers.h:111
int refCount
Definition: juce_core.cpp:808
#define JUCE_DECLARE_NON_COPYABLE(className)
Definition: juce_PlatformDefs.h:191
uint32 getExitCode() const noexcept
Definition: juce_posix_SharedCode.h:1106
Definition: juce_File.h:822
static void JUCE_CALLTYPE sleep(int milliseconds)
Definition: juce_posix_SharedCode.h:135
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
Definition: juce_PlatformDefs.h:198
Definition: juce_android_JNIHelpers.h:381
Definition: juce_HeapBlock.h:90
WaitableEvent(bool manualReset=false) noexcept
Definition: juce_posix_SharedCode.h:47
Definition: juce_posix_SharedCode.h:1148
Result truncate()
Definition: juce_posix_SharedCode.h:520
int handle
Definition: juce_core.cpp:808
bool existsAsFile() const
Definition: juce_posix_SharedCode.h:278
static File JUCE_CALLTYPE getSpecialLocation(const SpecialLocationType type)
Definition: juce_android_Files.cpp:49
~InterProcessLock()
Definition: juce_posix_SharedCode.h:815
~FileInputStream()
Definition: juce_posix_SharedCode.h:417
const String & getFullPathName() const noexcept
Definition: juce_File.h:150
#define nullptr
Definition: juce_CompilerSupport.h:151
File getChildFile(StringRef relativeOrAbsolutePath) const
Definition: juce_File.cpp:358
int read(void *const dest, const int numBytes) noexcept
Definition: juce_posix_SharedCode.h:1084
ElementType * getRawDataPointer() noexcept
Definition: juce_Array.h:319
void closeFile()
Definition: juce_posix_SharedCode.h:789
Pimpl(HighResolutionTimer &t)
Definition: juce_posix_SharedCode.h:1150
void exit() const noexcept
Definition: juce_posix_SharedCode.h:44
Definition: juce_File.h:45
CharType * getAddress() const noexcept
Definition: juce_CharPointer_UTF8.h:74
int childPID
Definition: juce_posix_SharedCode.h:1120
void close()
Definition: juce_posix_SharedCode.h:987
const char * toRawUTF8() const
Definition: juce_String.cpp:2061
int64 juce_fileSetPosition(void *handle, int64 pos)
Definition: juce_posix_SharedCode.h:399
~Pimpl()
Definition: juce_posix_SharedCode.h:742
~MemoryMappedFile()
Definition: juce_posix_SharedCode.h:571
void stop()
Definition: juce_posix_SharedCode.h:1183
bool createLockFile(const File &file, const int timeOutMillisecs)
Definition: juce_posix_SharedCode.h:747
wchar_t juce_wchar
Definition: juce_CharacterFunctions.h:49
Definition: juce_posix_SharedCode.h:1004
GlobalRef activity
Definition: juce_android_JNIHelpers.h:249
static Result fail(const String &errorMessage) noexcept
Definition: juce_Result.cpp:70
Definition: juce_posix_SharedCode.h:722