JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_SharedCode_posix.h
Go to the documentation of this file.
1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
37
40bool CriticalSection::tryEnter() const noexcept { return pthread_mutex_trylock (&lock) == 0; }
42
43//==============================================================================
45{
46 struct timespec time;
47 time.tv_sec = millisecs / 1000;
48 time.tv_nsec = (millisecs % 1000) * 1000000;
49 nanosleep (&time, nullptr);
50}
51
53{
54 #if JUCE_ANDROID
56 #else
58 #endif
59}
60
61
62#if JUCE_MAC || JUCE_LINUX || JUCE_BSD
64{
65 rlimit lim;
66
67 if (getrlimit (RLIMIT_NOFILE, &lim) == 0)
68 {
69 if (newMaxNumber <= 0 && lim.rlim_cur == RLIM_INFINITY && lim.rlim_max == RLIM_INFINITY)
70 return true;
71
72 if (newMaxNumber > 0 && lim.rlim_cur >= (rlim_t) newMaxNumber)
73 return true;
74 }
75
76 lim.rlim_cur = lim.rlim_max = newMaxNumber <= 0 ? RLIM_INFINITY : (rlim_t) newMaxNumber;
77 return setrlimit (RLIMIT_NOFILE, &lim) == 0;
78}
79
81{
83 {
84 #ifndef JUCE_PREFERRED_MAX_FILE_HANDLES
85 enum { JUCE_PREFERRED_MAX_FILE_HANDLES = 8192 };
86 #endif
87
88 // Try to give our app a decent number of file handles by default
90 {
91 for (int num = JUCE_PREFERRED_MAX_FILE_HANDLES; num > 256; num -= 1024)
93 break;
94 }
95 }
96};
97
99#endif
100
101//==============================================================================
102#if JUCE_ALLOW_STATIC_NULL_VARIABLES
103
104JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
105
106const juce_wchar File::separator = '/';
107const StringRef File::separatorString ("/");
108
109JUCE_END_IGNORE_WARNINGS_GCC_LIKE
110
111#endif
112
115
116
117//==============================================================================
119{
121
122 char localBuffer[1024];
123 auto cwd = getcwd (localBuffer, sizeof (localBuffer) - 1);
124 size_t bufferSize = 4096;
125
126 while (cwd == nullptr && errno == ERANGE)
127 {
128 heapBuffer.malloc (bufferSize);
129 cwd = getcwd (heapBuffer, bufferSize - 1);
130 bufferSize += 1024;
131 }
132
133 return File (CharPointer_UTF8 (cwd));
134}
135
137{
138 return chdir (getFullPathName().toUTF8()) == 0;
139}
140
141//==============================================================================
142// The unix siginterrupt function is deprecated - this does the same job.
143int juce_siginterrupt ([[maybe_unused]] int sig, [[maybe_unused]] int flag)
144{
145 #if JUCE_WASM
146 return 0;
147 #else
148 #if JUCE_ANDROID
149 using juce_sigactionflags_type = unsigned long;
150 #else
152 #endif
153
154 struct ::sigaction act;
155 (void) ::sigaction (sig, nullptr, &act);
156
157 if (flag != 0)
158 act.sa_flags &= static_cast<juce_sigactionflags_type> (~SA_RESTART);
159 else
160 act.sa_flags |= static_cast<juce_sigactionflags_type> (SA_RESTART);
161
162 return ::sigaction (sig, &act, nullptr);
163 #endif
164}
165
166//==============================================================================
167namespace
168{
169 #if JUCE_LINUX || (JUCE_IOS && (! TARGET_OS_MACCATALYST) && (! __DARWIN_ONLY_64_BIT_INO_T)) // (this iOS stuff is to avoid a simulator bug)
170 using juce_statStruct = struct stat64;
171 #define JUCE_STAT stat64
172 #else
173 using juce_statStruct = struct stat;
174 #define JUCE_STAT stat
175 #endif
176
177 bool juce_stat (const String& fileName, juce_statStruct& info)
178 {
179 return fileName.isNotEmpty()
180 && JUCE_STAT (fileName.toUTF8(), &info) == 0;
181 }
182
183 #if ! JUCE_WASM
184 // if this file doesn't exist, find a parent of it that does..
185 bool juce_doStatFS (File f, struct statfs& result)
186 {
187 for (int i = 5; --i >= 0;)
188 {
189 if (f.exists())
190 break;
191
192 f = f.getParentDirectory();
193 }
194
195 return statfs (f.getFullPathName().toUTF8(), &result) == 0;
196 }
197
198 #if JUCE_MAC || JUCE_IOS
199 static int64 getCreationTime (const juce_statStruct& s) noexcept { return (int64) s.st_birthtime; }
200 #else
201 static int64 getCreationTime (const juce_statStruct& s) noexcept { return (int64) s.st_ctime; }
202 #endif
203
204 void updateStatInfoForFile (const String& path, bool* isDir, int64* fileSize,
205 Time* modTime, Time* creationTime, bool* isReadOnly)
206 {
207 if (isDir != nullptr || fileSize != nullptr || modTime != nullptr || creationTime != nullptr)
208 {
209 juce_statStruct info;
210 const bool statOk = juce_stat (path, info);
211
212 if (isDir != nullptr) *isDir = statOk && ((info.st_mode & S_IFDIR) != 0);
213 if (fileSize != nullptr) *fileSize = statOk ? (int64) info.st_size : 0;
214 if (modTime != nullptr) *modTime = Time (statOk ? (int64) info.st_mtime * 1000 : 0);
215 if (creationTime != nullptr) *creationTime = Time (statOk ? getCreationTime (info) * 1000 : 0);
216 }
217
218 if (isReadOnly != nullptr)
219 *isReadOnly = access (path.toUTF8(), W_OK) != 0;
220 }
221 #endif
222
223 Result getResultForErrno()
224 {
225 return Result::fail (String (strerror (errno)));
226 }
227
228 Result getResultForReturnValue (int value)
229 {
230 return value == -1 ? getResultForErrno() : Result::ok();
231 }
232
233 int getFD (void* handle) noexcept { return (int) (pointer_sized_int) handle; }
234 void* fdToVoidPointer (int fd) noexcept { return (void*) (pointer_sized_int) fd; }
235}
236
238{
239 juce_statStruct info;
240
241 return fullPath.isNotEmpty()
242 && (juce_stat (fullPath, info) && ((info.st_mode & S_IFDIR) != 0));
243}
244
245bool File::exists() const
246{
247 return fullPath.isNotEmpty()
248 && access (fullPath.toUTF8(), F_OK) == 0;
249}
250
252{
253 return exists() && ! isDirectory();
254}
255
257{
258 juce_statStruct info;
259 return juce_stat (fullPath, info) ? info.st_size : 0;
260}
261
263{
264 juce_statStruct info;
265 return juce_stat (fullPath, info) ? (uint64) info.st_ino : 0;
266}
267
268static bool hasEffectiveRootFilePermissions()
269{
270 #if JUCE_LINUX || JUCE_BSD
271 return geteuid() == 0;
272 #else
273 return false;
274 #endif
275}
276
277//==============================================================================
279{
280 if (exists())
281 return (hasEffectiveRootFilePermissions()
282 || access (fullPath.toUTF8(), W_OK) == 0);
283
284 if ((! isDirectory()) && fullPath.containsChar (getSeparatorChar()))
286
287 return false;
288}
289
291{
292 return fullPath.isNotEmpty()
293 && access (fullPath.toUTF8(), R_OK) == 0;
294}
295
296static bool setFileModeFlags (const String& fullPath, mode_t flags, bool shouldSet) noexcept
297{
298 juce_statStruct info;
299
300 if (! juce_stat (fullPath, info))
301 return false;
302
303 info.st_mode &= 0777;
304
305 if (shouldSet)
306 info.st_mode |= flags;
307 else
308 info.st_mode &= ~flags;
309
310 return chmod (fullPath.toUTF8(), (mode_t) info.st_mode) == 0;
311}
312
313bool File::setFileReadOnlyInternal (bool shouldBeReadOnly) const
314{
315 // Hmm.. should we give global write permission or just the current user?
316 return setFileModeFlags (fullPath, S_IWUSR | S_IWGRP | S_IWOTH, ! shouldBeReadOnly);
317}
318
319bool File::setFileExecutableInternal (bool shouldBeExecutable) const
320{
321 return setFileModeFlags (fullPath, S_IXUSR | S_IXGRP | S_IXOTH, shouldBeExecutable);
322}
323
324void File::getFileTimesInternal (int64& modificationTime, int64& accessTime, int64& creationTime) const
325{
326 modificationTime = 0;
327 accessTime = 0;
328 creationTime = 0;
329
330 juce_statStruct info;
331
332 if (juce_stat (fullPath, info))
333 {
334 #if JUCE_MAC || (JUCE_IOS && __DARWIN_ONLY_64_BIT_INO_T)
335 modificationTime = (int64) info.st_mtimespec.tv_sec * 1000 + info.st_mtimespec.tv_nsec / 1000000;
336 accessTime = (int64) info.st_atimespec.tv_sec * 1000 + info.st_atimespec.tv_nsec / 1000000;
337 creationTime = (int64) info.st_birthtimespec.tv_sec * 1000 + info.st_birthtimespec.tv_nsec / 1000000;
338 #else
339 modificationTime = (int64) info.st_mtime * 1000;
340 accessTime = (int64) info.st_atime * 1000;
341 #if JUCE_IOS
342 creationTime = (int64) info.st_birthtime * 1000;
343 #else
344 creationTime = (int64) info.st_ctime * 1000;
345 #endif
346 #endif
347 }
348}
349
350bool File::setFileTimesInternal (int64 modificationTime, int64 accessTime, int64 /*creationTime*/) const
351{
352 #if ! JUCE_WASM
353 juce_statStruct info;
354
355 if ((modificationTime != 0 || accessTime != 0) && juce_stat (fullPath, info))
356 {
357 #if JUCE_MAC || (JUCE_IOS && __DARWIN_ONLY_64_BIT_INO_T)
358 struct timeval times[2];
359
360 bool setModificationTime = (modificationTime != 0);
361 bool setAccessTime = (accessTime != 0);
362
363 times[0].tv_sec = setAccessTime ? static_cast<__darwin_time_t> (accessTime / 1000)
364 : info.st_atimespec.tv_sec;
365
366 times[0].tv_usec = setAccessTime ? static_cast<__darwin_suseconds_t> ((accessTime % 1000) * 1000)
368
369 times[1].tv_sec = setModificationTime ? static_cast<__darwin_time_t> (modificationTime / 1000)
370 : info.st_mtimespec.tv_sec;
371
372 times[1].tv_usec = setModificationTime ? static_cast<__darwin_suseconds_t> ((modificationTime % 1000) * 1000)
374
375 return utimes (fullPath.toUTF8(), times) == 0;
376 #else
377 struct utimbuf times;
378 times.actime = accessTime != 0 ? static_cast<time_t> (accessTime / 1000) : static_cast<time_t> (info.st_atime);
379 times.modtime = modificationTime != 0 ? static_cast<time_t> (modificationTime / 1000) : static_cast<time_t> (info.st_mtime);
380
381 return utime (fullPath.toUTF8(), &times) == 0;
382 #endif
383 }
384 #endif
385
386 return false;
387}
388
390{
391 if (! isSymbolicLink())
392 {
393 if (! exists())
394 return true;
395
396 if (isDirectory())
397 return rmdir (fullPath.toUTF8()) == 0;
398 }
399
400 return remove (fullPath.toUTF8()) == 0;
401}
402
403bool File::moveInternal (const File& dest) const
404{
405 if (rename (fullPath.toUTF8(), dest.getFullPathName().toUTF8()) == 0)
406 return true;
407
408 if (isNonEmptyDirectory())
409 return false;
410
411 if (hasWriteAccess() && copyInternal (dest))
412 {
413 if (deleteFile())
414 return true;
415
416 dest.deleteFile();
417 }
418
419 return false;
420}
421
422bool File::replaceInternal (const File& dest) const
423{
424 return moveInternal (dest);
425}
426
427Result File::createDirectoryInternal (const String& fileName) const
428{
429 return getResultForReturnValue (mkdir (fileName.toUTF8(), 0777));
430}
431
432//==============================================================================
433int64 juce_fileSetPosition (void* handle, int64 pos)
434{
435 if (handle != nullptr && lseek (getFD (handle), (off_t) pos, SEEK_SET) == pos)
436 return pos;
437
438 return -1;
439}
440
441void FileInputStream::openHandle()
442{
443 auto f = open (file.getFullPathName().toUTF8(), O_RDONLY);
444
445 if (f != -1)
446 fileHandle = fdToVoidPointer (f);
447 else
448 status = getResultForErrno();
449}
450
452{
453 if (fileHandle != nullptr)
454 close (getFD (fileHandle));
455}
456
457size_t FileInputStream::readInternal (void* buffer, size_t numBytes)
458{
459 ssize_t result = 0;
460
461 if (fileHandle != nullptr)
462 {
463 result = ::read (getFD (fileHandle), buffer, numBytes);
464
465 if (result < 0)
466 {
467 status = getResultForErrno();
468 result = 0;
469 }
470 }
471
472 return (size_t) result;
473}
474
475//==============================================================================
476void FileOutputStream::openHandle()
477{
478 if (file.exists())
479 {
480 auto f = open (file.getFullPathName().toUTF8(), O_RDWR);
481
482 if (f != -1)
483 {
484 currentPosition = lseek (f, 0, SEEK_END);
485
486 if (currentPosition >= 0)
487 {
488 fileHandle = fdToVoidPointer (f);
489 }
490 else
491 {
492 status = getResultForErrno();
493 close (f);
494 }
495 }
496 else
497 {
498 status = getResultForErrno();
499 }
500 }
501 else
502 {
503 auto f = open (file.getFullPathName().toUTF8(), O_RDWR | O_CREAT, 00644);
504
505 if (f != -1)
506 fileHandle = fdToVoidPointer (f);
507 else
508 status = getResultForErrno();
509 }
510}
511
512void FileOutputStream::closeHandle()
513{
514 if (fileHandle != nullptr)
515 {
516 close (getFD (fileHandle));
517 fileHandle = nullptr;
518 }
519}
520
521ssize_t FileOutputStream::writeInternal (const void* data, size_t numBytes)
522{
523 if (fileHandle == nullptr)
524 return 0;
525
526 auto result = ::write (getFD (fileHandle), data, numBytes);
527
528 if (result == -1)
529 status = getResultForErrno();
530
531 return (ssize_t) result;
532}
533
534#ifndef JUCE_ANDROID
535void FileOutputStream::flushInternal()
536{
537 if (fileHandle != nullptr && fsync (getFD (fileHandle)) == -1)
538 status = getResultForErrno();
539}
540#endif
541
543{
544 if (fileHandle == nullptr)
545 return status;
546
547 flush();
548 return getResultForReturnValue (ftruncate (getFD (fileHandle), (off_t) currentPosition));
549}
550
551//==============================================================================
552String SystemStats::getEnvironmentVariable (const String& name, const String& defaultValue)
553{
554 if (auto s = ::getenv (name.toUTF8()))
555 return String::fromUTF8 (s);
556
557 return defaultValue;
558}
559
560//==============================================================================
561#if ! JUCE_WASM
562void MemoryMappedFile::openInternal (const File& file, AccessMode mode, bool exclusive)
563{
564 jassert (mode == readOnly || mode == readWrite);
565
566 if (range.getStart() > 0)
567 {
569 range.setStart (range.getStart() - (range.getStart() % pageSize));
570 }
571
572 auto filename = file.getFullPathName().toUTF8();
573
574 if (mode == readWrite)
575 fileHandle = open (filename, O_CREAT | O_RDWR, 00644);
576 else
577 fileHandle = open (filename, O_RDONLY);
578
579 if (fileHandle != -1)
580 {
581 auto m = mmap (nullptr, (size_t) range.getLength(),
582 mode == readWrite ? (PROT_READ | PROT_WRITE) : PROT_READ,
583 exclusive ? MAP_PRIVATE : MAP_SHARED, fileHandle,
584 (off_t) range.getStart());
585
586 if (m != MAP_FAILED)
587 {
588 address = m;
589 madvise (m, (size_t) range.getLength(), MADV_SEQUENTIAL);
590 }
591 else
592 {
593 range = Range<int64>();
594 }
595
596 close (fileHandle);
597 fileHandle = 0;
598 }
599}
600
602{
603 if (address != nullptr)
604 munmap (address, (size_t) range.getLength());
605
606 if (fileHandle != 0)
607 close (fileHandle);
608}
609
610//==============================================================================
611File juce_getExecutableFile();
612File juce_getExecutableFile()
613{
614 struct DLAddrReader
615 {
616 static String getFilename()
617 {
619
620 auto localSymbol = (void*) juce_getExecutableFile;
622 return CharPointer_UTF8 (exeInfo.dli_fname);
623 }
624 };
625
626 static String filename = DLAddrReader::getFilename();
628}
629
630//==============================================================================
632{
633 struct statfs buf;
634
635 if (juce_doStatFS (*this, buf))
636 return (int64) buf.f_bsize * (int64) buf.f_bavail; // Note: this returns space available to non-super user
637
638 return 0;
639}
640
642{
643 struct statfs buf;
644
645 if (juce_doStatFS (*this, buf))
646 return (int64) buf.f_bsize * (int64) buf.f_blocks;
647
648 return 0;
649}
650
652{
653 #if JUCE_MAC
654 struct VolAttrBuf
655 {
656 u_int32_t length;
657 attrreference_t mountPointRef;
658 char mountPointSpace[MAXPATHLEN];
659 } attrBuf;
660
661 struct attrlist attrList;
662 zerostruct (attrList); // (can't use "= {}" on this object because it's a C struct)
663 attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
665
666 File f (*this);
667
668 for (;;)
669 {
671 return String::fromUTF8 (((const char*) &attrBuf.mountPointRef) + attrBuf.mountPointRef.attr_dataoffset,
672 (int) attrBuf.mountPointRef.attr_length);
673
674 auto parent = f.getParentDirectory();
675
676 if (f == parent)
677 break;
678
679 f = parent;
680 }
681 #endif
682
683 return {};
684}
685
687{
688 return 0;
689}
690
691#endif
692
693//==============================================================================
694#if ! JUCE_IOS
695void juce_runSystemCommand (const String&);
696void juce_runSystemCommand (const String& command)
697{
698 [[maybe_unused]] int result = system (command.toUTF8());
699}
700
701String juce_getOutputFromCommand (const String&);
702String juce_getOutputFromCommand (const String& command)
703{
704 // slight bodge here, as we just pipe the output into a temp file and read it...
707
708 juce_runSystemCommand (command + " > " + tempFile.getFullPathName());
709
710 auto result = tempFile.loadFileAsString();
711 tempFile.deleteFile();
712 return result;
713}
714#endif
715
716//==============================================================================
717#if JUCE_IOS
718class InterProcessLock::Pimpl
719{
720public:
721 Pimpl (const String&, int) {}
722
723 int handle = 1, refCount = 1; // On iOS just fake success..
724};
725
726#else
727
729{
730public:
732 {
733 #if JUCE_MAC
734 if (! createLockFile (File ("~/Library/Caches/com.juce.locks").getChildFile (lockName), timeOutMillisecs))
735 // Fallback if the user's home folder is on a network drive with no ability to lock..
736 createLockFile (File ("/tmp/com.juce.locks").getChildFile (lockName), timeOutMillisecs);
737
738 #else
739 File tempFolder ("/var/tmp");
740
741 if (! tempFolder.isDirectory())
742 tempFolder = "/tmp";
743
744 createLockFile (tempFolder.getChildFile (lockName), timeOutMillisecs);
745 #endif
746 }
747
748 ~Pimpl()
749 {
750 closeFile();
751 }
752
753 bool createLockFile (const File& file, int timeOutMillisecs)
754 {
755 file.create();
756 handle = open (file.getFullPathName().toUTF8(), O_RDWR);
757
758 if (handle != 0)
759 {
760 struct flock fl;
761 zerostruct (fl);
762
763 fl.l_whence = SEEK_SET;
764 fl.l_type = F_WRLCK;
765
766 auto endTime = Time::currentTimeMillis() + timeOutMillisecs;
767
768 for (;;)
769 {
770 auto result = fcntl (handle, F_SETLK, &fl);
771
772 if (result >= 0)
773 return true;
774
775 auto error = errno;
776
777 if (error != EINTR)
778 {
779 if (error == EBADF || error == ENOTSUP)
780 return false;
781
782 if (timeOutMillisecs == 0
783 || (timeOutMillisecs > 0 && Time::currentTimeMillis() >= endTime))
784 break;
785
786 Thread::sleep (10);
787 }
788 }
789 }
790
791 closeFile();
792 return true; // only false if there's a file system error. Failure to lock still returns true.
793 }
794
795 void closeFile()
796 {
797 if (handle != 0)
798 {
799 struct flock fl;
800 zerostruct (fl);
801
802 fl.l_whence = SEEK_SET;
803 fl.l_type = F_UNLCK;
804
805 while (! (fcntl (handle, F_SETLKW, &fl) >= 0 || errno != EINTR))
806 {}
807
808 close (handle);
809 handle = 0;
810 }
811 }
812
813 int handle = 0, refCount = 1;
814};
815#endif
816
818{
819}
820
824
826{
827 const ScopedLock sl (lock);
828
829 if (pimpl == nullptr)
830 {
831 pimpl.reset (new Pimpl (name, timeOutMillisecs));
832
833 if (pimpl->handle == 0)
834 pimpl.reset();
835 }
836 else
837 {
838 pimpl->refCount++;
839 }
840
841 return pimpl != nullptr;
842}
843
845{
846 const ScopedLock sl (lock);
847
848 // Trying to release the lock too many times!
849 jassert (pimpl != nullptr);
850
851 if (pimpl != nullptr && --(pimpl->refCount) == 0)
852 pimpl.reset();
853}
854
856{
857public:
858 explicit PosixThreadAttribute (size_t stackSize)
859 {
860 if (valid && stackSize != 0)
861 pthread_attr_setstacksize (&attr, stackSize);
862 }
863
865 {
866 if (valid)
867 pthread_attr_destroy (&attr);
868 }
869
870 auto* get() { return valid ? &attr : nullptr; }
871
872private:
873 pthread_attr_t attr;
874 bool valid { pthread_attr_init (&attr) == 0 };
875};
876
878{
879public:
880 static PosixSchedulerPriority findCurrentSchedulerAndPriority()
881 {
882 int scheduler{};
883 sched_param param{};
884 pthread_getschedparam (pthread_self(), &scheduler, &param);
885 return { scheduler, param.sched_priority };
886 }
887
888 static PosixSchedulerPriority getNativeSchedulerAndPriority (const Optional<Thread::RealtimeOptions>& rt,
890 {
891 const auto isRealtime = rt.hasValue();
892
893 const auto priority = [&]
894 {
895 if (isRealtime)
896 {
897 const auto min = jmax (0, sched_get_priority_min (SCHED_RR));
898 const auto max = jmax (1, sched_get_priority_max (SCHED_RR));
899
900 return jmap (rt->getPriority(), 0, 10, min, max);
901 }
902
903 // We only use this helper if we're on an old macos/ios platform that might
904 // still respect legacy pthread priorities for SCHED_OTHER.
905 #if JUCE_MAC || JUCE_IOS
906 const auto min = jmax (0, sched_get_priority_min (SCHED_OTHER));
907 const auto max = jmax (0, sched_get_priority_max (SCHED_OTHER));
908
909 const auto p = [prio]
910 {
911 switch (prio)
912 {
913 case Thread::Priority::highest: return 4;
914 case Thread::Priority::high: return 3;
915 case Thread::Priority::normal: return 2;
916 case Thread::Priority::low: return 1;
917 case Thread::Priority::background: return 0;
918 }
919
920 return 3;
921 }();
922
923 if (min != 0 && max != 0)
924 return jmap (p, 0, 4, min, max);
925 #endif
926
927 return 0;
928 }();
929
930 #if JUCE_MAC || JUCE_IOS || JUCE_BSD
931 const auto scheduler = SCHED_OTHER;
932 #elif JUCE_LINUX
934 : SCHED_OTHER;
935 const auto scheduler = isRealtime ? SCHED_RR : backgroundSched;
936 #else
937 const auto scheduler = 0;
938 #endif
939
940 return { scheduler, priority };
941 }
942
943 void apply ([[maybe_unused]] PosixThreadAttribute& attr) const
944 {
945 #if JUCE_LINUX || JUCE_BSD
946 const struct sched_param param { getPriority() };
947
949 pthread_attr_setschedpolicy (attr.get(), getScheduler());
950 pthread_attr_setschedparam (attr.get(), &param);
951 #endif
952 }
953
954 constexpr int getScheduler() const { return scheduler; }
955 constexpr int getPriority() const { return priority; }
956
957private:
959 : scheduler (schedulerIn), priority (priorityIn) {}
960
961 int scheduler;
962 int priority;
963};
964
965static void* makeThreadHandle (PosixThreadAttribute& attr, void* userData, void* (*threadEntryProc) (void*))
966{
967 pthread_t handle = {};
968
969 const auto status = pthread_create (&handle, attr.get(), threadEntryProc, userData);
970
971 if (status != 0)
972 return nullptr;
973
974 pthread_detach (handle);
975 return (void*) handle;
976}
977
978void Thread::closeThreadHandle()
979{
980 threadId = {};
981 threadHandle = nullptr;
982}
983
985{
986 #if JUCE_IOS || JUCE_MAC
988 {
989 [[NSThread currentThread] setName: juceStringToNS (name)];
990 }
991 #elif JUCE_LINUX || JUCE_BSD || JUCE_ANDROID
992 #if (JUCE_BSD \
993 || (JUCE_LINUX && (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012) \
994 || (JUCE_ANDROID && __ANDROID_API__ >= 9))
996 #else
997 prctl (PR_SET_NAME, name.toRawUTF8(), 0, 0, 0);
998 #endif
999 #endif
1000}
1001
1006
1008{
1009 sched_yield();
1010}
1011
1012//==============================================================================
1013/* Remove this macro if you're having problems compiling the cpu affinity
1014 calls (the API for these has changed about quite a bit in various Linux
1015 versions, and a lot of distros seem to ship with obsolete versions)
1016*/
1017#if defined (CPU_ISSET) && ! defined (SUPPORT_AFFINITIES)
1018 #define SUPPORT_AFFINITIES 1
1019#endif
1020
1022{
1023 #if SUPPORT_AFFINITIES
1025 CPU_ZERO (&affinity);
1026
1027 for (int i = 0; i < 32; ++i)
1028 {
1029 if ((affinityMask & (uint32) (1 << i)) != 0)
1030 {
1031 // GCC 12 on FreeBSD complains about CPU_SET irrespective of
1032 // the type of the first argument
1033 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wsign-conversion")
1034 CPU_SET ((size_t) i, &affinity);
1035 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
1036 }
1037 }
1038
1039 #if (! JUCE_ANDROID) && ((! (JUCE_LINUX || JUCE_BSD)) || ((__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2004))
1041 #elif JUCE_ANDROID
1043 #else
1044 // NB: this call isn't really correct because it sets the affinity of the process,
1045 // (getpid) not the thread (not gettid). But it's included here as a fallback for
1046 // people who are using ridiculously old versions of glibc
1048 #endif
1049
1050 sched_yield();
1051
1052 #else
1053 // affinities aren't supported because either the appropriate header files weren't found,
1054 // or the SUPPORT_AFFINITIES macro was turned off
1056 #endif
1057}
1058
1059//==============================================================================
1060#if ! JUCE_WASM
1062{
1063 close();
1064 handle = dlopen (name.isEmpty() ? nullptr : name.toUTF8().getAddress(), RTLD_LOCAL | RTLD_NOW);
1065 return handle != nullptr;
1066}
1067
1069{
1070 if (handle != nullptr)
1071 {
1072 dlclose (handle);
1073 handle = nullptr;
1074 }
1075}
1076
1077void* DynamicLibrary::getFunction (const String& functionName) noexcept
1078{
1079 return handle != nullptr ? dlsym (handle, functionName.toUTF8()) : nullptr;
1080}
1081
1082//==============================================================================
1083#if JUCE_LINUX || JUCE_ANDROID
1084static String readPosixConfigFileValue (const char* file, const char* key)
1085{
1086 StringArray lines;
1087 File (file).readLines (lines);
1088
1089 for (int i = lines.size(); --i >= 0;) // (NB - it's important that this runs in reverse order)
1090 if (lines[i].upToFirstOccurrenceOf (":", false, false).trim().equalsIgnoreCase (key))
1091 return lines[i].fromFirstOccurrenceOf (":", false, false).trim();
1092
1093 return {};
1094}
1095#endif
1096
1097
1098//==============================================================================
1100{
1101public:
1102 ActiveProcess (const StringArray& arguments, int streamFlags)
1103 {
1104 auto exe = arguments[0].unquoted();
1105
1106 // Looks like you're trying to launch a non-existent exe or a folder (perhaps on OSX
1107 // you're trying to launch the .app folder rather than the actual binary inside it?)
1108 jassert (File::getCurrentWorkingDirectory().getChildFile (exe).existsAsFile()
1109 || ! exe.containsChar (File::getSeparatorChar()));
1110
1111 int pipeHandles[2] = {};
1112
1113 if (pipe (pipeHandles) == 0)
1114 {
1115 auto result = fork();
1116
1117 if (result < 0)
1118 {
1119 close (pipeHandles[0]);
1120 close (pipeHandles[1]);
1121 }
1122 else if (result == 0)
1123 {
1124 // we're the child process..
1125 close (pipeHandles[0]); // close the read handle
1126
1127 if ((streamFlags & wantStdOut) != 0)
1128 dup2 (pipeHandles[1], STDOUT_FILENO); // turns the pipe into stdout
1129 else
1130 dup2 (open ("/dev/null", O_WRONLY), STDOUT_FILENO);
1131
1132 if ((streamFlags & wantStdErr) != 0)
1134 else
1135 dup2 (open ("/dev/null", O_WRONLY), STDERR_FILENO);
1136
1137 close (pipeHandles[1]);
1138
1140
1141 for (auto& arg : arguments)
1142 if (arg.isNotEmpty())
1143 argv.add (const_cast<char*> (arg.toRawUTF8()));
1144
1145 argv.add (nullptr);
1146
1147 execvp (exe.toRawUTF8(), argv.getRawDataPointer());
1148 _exit (-1);
1149 }
1150 else
1151 {
1152 // we're the parent process..
1153 childPID = result;
1154 pipeHandle = pipeHandles[0];
1155 close (pipeHandles[1]); // close the write handle
1156 }
1157 }
1158 }
1159
1161 {
1162 if (readHandle != nullptr)
1163 fclose (readHandle);
1164
1165 if (pipeHandle != 0)
1166 close (pipeHandle);
1167 }
1168
1169 bool isRunning() noexcept
1170 {
1171 if (childPID == 0)
1172 return false;
1173
1174 int childState = 0;
1175 auto pid = waitpid (childPID, &childState, WNOHANG);
1176
1177 if (pid == 0)
1178 return true;
1179
1180 if (WIFEXITED (childState))
1181 {
1182 exitCode = WEXITSTATUS (childState);
1183 return false;
1184 }
1185
1186 return ! WIFSIGNALED (childState);
1187 }
1188
1189 int read (void* dest, int numBytes) noexcept
1190 {
1191 jassert (dest != nullptr && numBytes > 0);
1192
1193 #ifdef fdopen
1194 #error // some crazy 3rd party headers (e.g. zlib) define this function as NULL!
1195 #endif
1196
1197 if (readHandle == nullptr && childPID != 0)
1198 readHandle = fdopen (pipeHandle, "r");
1199
1200 if (readHandle != nullptr)
1201 {
1202 for (;;)
1203 {
1204 auto numBytesRead = (int) fread (dest, 1, (size_t) numBytes, readHandle);
1205
1206 if (numBytesRead > 0 || feof (readHandle))
1207 return numBytesRead;
1208
1209 // signal occurred during fread() so try again
1210 if (ferror (readHandle) && errno == EINTR)
1211 continue;
1212
1213 break;
1214 }
1215 }
1216
1217 return 0;
1218 }
1219
1220 bool killProcess() const noexcept
1221 {
1222 return ::kill (childPID, SIGKILL) == 0;
1223 }
1224
1225 uint32 getExitCode() noexcept
1226 {
1227 if (exitCode >= 0)
1228 return (uint32) exitCode;
1229
1230 if (childPID != 0)
1231 {
1232 int childState = 0;
1233 auto pid = waitpid (childPID, &childState, WNOHANG);
1234
1235 if (pid >= 0 && WIFEXITED (childState))
1236 {
1237 exitCode = WEXITSTATUS (childState);
1238 return (uint32) exitCode;
1239 }
1240 }
1241
1242 return 0;
1243 }
1244
1245 int childPID = 0;
1246 int pipeHandle = 0;
1247 int exitCode = -1;
1248 FILE* readHandle = {};
1249
1251};
1252
1253bool ChildProcess::start (const String& command, int streamFlags)
1254{
1255 return start (StringArray::fromTokens (command, true), streamFlags);
1256}
1257
1259{
1260 if (args.size() == 0)
1261 return false;
1262
1263 activeProcess.reset (new ActiveProcess (args, streamFlags));
1264
1265 if (activeProcess->childPID == 0)
1266 activeProcess.reset();
1267
1268 return activeProcess != nullptr;
1269}
1270
1271#endif
1272
1273} // namespace juce
#define ERANGE
T _Exit(T... args)
_exit
access
chdir
chmod
Holds a resizable array of primitive or copy-by-value objects.
Definition juce_Array.h:56
void add(const ElementType &newElement)
Appends a new element at the end of the array.
Definition juce_Array.h:418
Wraps a pointer to a null-terminated UTF-8 character string, and provides various methods to operate ...
CharType * getAddress() const noexcept
Returns the address that this pointer is pointing to.
bool start(const String &command, int streamFlags=wantStdOut|wantStdErr)
Attempts to launch a child process command.
bool tryEnter() const noexcept
Attempts to lock this critical section without blocking.
~CriticalSection() noexcept
Destructor.
CriticalSection() noexcept
Creates a CriticalSection object.
void enter() const noexcept
Acquires the lock.
void exit() const noexcept
Releases the lock.
void * getFunction(const String &functionName) noexcept
Tries to find a named function in the currently-open DLL, and returns a pointer to it.
bool open(const String &name)
Opens a DLL.
void close()
Releases the currently-open DLL, or has no effect if none was open.
~FileInputStream() override
Destructor.
Result truncate()
Attempts to truncate the file to the current write position.
void flush() override
If the stream is using a buffer, this will ensure it gets written out to the destination.
Represents a local file or directory.
Definition juce_File.h:45
int getVolumeSerialNumber() const
Returns the serial number of the volume on which this file lives.
bool isSymbolicLink() const
Returns true if this file is a link or alias that can be followed using getLinkedTarget().
bool isDirectory() const
Checks whether the file is a directory that exists.
bool setAsCurrentWorkingDirectory() const
Sets the current working directory to be this file.
static StringRef getSeparatorString()
The system-specific file separator character, as a string.
int64 getVolumeTotalSize() const
Returns the total size of the drive that contains this file.
int64 getBytesFreeOnVolume() const
Returns the number of bytes free on the drive that this file lives on.
bool hasWriteAccess() const
Checks whether a file can be created or written to.
bool existsAsFile() const
Checks whether the file exists and is a file rather than a directory.
int64 getSize() const
Returns the size of the file in bytes.
const String & getFullPathName() const noexcept
Returns the complete, absolute path of this file.
Definition juce_File.h:153
File getChildFile(StringRef relativeOrAbsolutePath) const
Returns a file that represents a relative (or absolute) sub-path of the current one.
void readLines(StringArray &destLines) const
Reads the contents of this file as text and splits it into lines, which are appended to the given Str...
static File getCurrentWorkingDirectory()
Returns the current working directory.
@ tempDirectory
The folder that should be used for temporary files.
Definition juce_File.h:919
Result create() const
Creates an empty file if it doesn't already exist.
File getNonexistentChildFile(const String &prefix, const String &suffix, bool putNumbersInBrackets=true) const
Chooses a filename relative to this one that doesn't already exist.
static File JUCE_CALLTYPE getSpecialLocation(const SpecialLocationType type)
Finds the location of a special type of file or directory, such as a home folder or documents folder.
bool hasReadAccess() const
Checks whether a file can be read.
File getParentDirectory() const
Returns the directory that contains this file or directory.
String getVolumeLabel() const
Finds the name of the drive on which this file lives.
uint64 getFileIdentifier() const
Returns a unique identifier for the file, if one is available.
static juce_wchar getSeparatorChar()
The system-specific file separator character.
File()=default
Creates an (invalid) file object.
bool deleteFile() const
Deletes a file.
bool exists() const
Checks whether the file actually exists.
Automatically locks and unlocks a mutex object.
Very simple container class to hold a pointer to some data on the heap.
void exit()
Releases the lock if it's currently held by this process.
bool enter(int timeOutMillisecs=-1)
Attempts to lock the critical section.
InterProcessLock(const String &name)
Creates a lock object.
@ readWrite
Indicates that the memory can be read and written to - changes that are made will be flushed back to ...
@ readOnly
Indicates that the memory can only be read.
A simple optional type.
static void JUCE_CALLTYPE terminate()
Kills the current process immediately.
static bool setMaxNumberOfFileHandles(int maxNumberOfFiles) noexcept
UNIX ONLY - Attempts to use setrlimit to change the maximum number of file handles that the app can o...
static Random & getSystemRandom() noexcept
The overhead of creating a new Random object is fairly small, but if you want to avoid it,...
constexpr ValueType getStart() const noexcept
Returns the start of the range.
Definition juce_Range.h:80
void setStart(const ValueType newStart) noexcept
Changes the start position of the range, leaving the end position unchanged.
Definition juce_Range.h:96
constexpr ValueType getLength() const noexcept
Returns the length of the range.
Definition juce_Range.h:83
Represents the 'success' or 'failure' of an operation, and holds an associated error message to descr...
Definition juce_Result.h:57
static Result fail(const String &errorMessage) noexcept
Creates a 'failure' result.
A special array for holding a list of strings.
static StringArray fromTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
Returns an array containing the tokens in a given string.
int size() const noexcept
Returns the number of strings in the array.
A simple class for holding temporary references to a string literal or String.
The JUCE String class!
Definition juce_String.h:53
bool isEmpty() const noexcept
Returns true if the string contains no characters.
const char * toRawUTF8() const
Returns a pointer to a UTF-8 version of this string.
bool containsChar(juce_wchar character) const noexcept
Tests whether the string contains a particular character.
static String toHexString(IntegerType number)
Returns a string representing this numeric value in hexadecimal.
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)
Creates a String from a UTF-8 encoded buffer.
CharPointer_UTF8 toUTF8() const
Returns a pointer to a UTF-8 version of this string.
bool isNotEmpty() const noexcept
Returns true if the string contains at least one character.
static String getEnvironmentVariable(const String &name, const String &defaultValue)
Returns an environment variable.
static void JUCE_CALLTYPE setCurrentThreadAffinityMask(uint32 affinityMask)
Changes the affinity mask for the caller thread.
void * ThreadID
A value type used for thread IDs.
static void JUCE_CALLTYPE yield()
Yields the current thread's CPU time-slot and allows a new thread to run.
static ThreadID JUCE_CALLTYPE getCurrentThreadId()
Returns an id that identifies the caller thread.
static void JUCE_CALLTYPE setCurrentThreadName(const String &newThreadName)
Changes the name of the caller thread.
Priority
The different runtime priorities of non-realtime threads.
Definition juce_Thread.h:54
@ low
Uses efficiency cores when possible.
@ high
Makes use of performance cores and higher clocks.
@ background
Restricted to efficiency cores on platforms that have them.
@ highest
The highest possible priority that isn't a dedicated realtime thread.
@ normal
The OS default.
static void JUCE_CALLTYPE sleep(int milliseconds)
Suspends the execution of the current thread until the specified timeout period has elapsed (note tha...
static int64 currentTimeMillis() noexcept
Returns the current system time.
close
dlclose
dlopen
dlsym
dup2
execvp
errno
fclose
fcntl
fdopen
feof
ferror
fork
fread
stat
ftruncate
utimes
getcwd
geteuid
getpid
setrlimit
#define JUCE_AUTORELEASEPOOL
A macro that can be used to easily declare a local ScopedAutoReleasePool object for RAII-based obj-C ...
#define jassert(expression)
Platform-independent assertion macro.
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and JUCE_LEAK_DETECTOR macro for ...
#define jassertfalse
This will always cause an assertion failure.
#define JUCE_CALLTYPE
This macro defines the C calling convention used as the standard for JUCE calls.
typedef int
lseek
mmap
munmap
JUCE Namespace.
void zerostruct(Type &structure) noexcept
Overwrites a structure or object with zeros.
Definition juce_Memory.h:32
int pointer_sized_int
A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it.
wchar_t juce_wchar
A platform-independent 32-bit unicode character type.
constexpr Type jmap(Type value0To1, Type targetRangeMin, Type targetRangeMax)
Remaps a normalised value (between 0 and 1) to a target range.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
unsigned long long uint64
A platform-independent 64-bit unsigned integer type.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
unsigned int uint32
A platform-independent 32-bit unsigned integer type.
long long int64
A platform-independent 64-bit integer type.
nanosleep
open
pipe
pthread_attr_destroy
pthread_attr_setschedparam
pthread_attr_setstacksize
pthread_create
pthread_detach
pthread_mutex_init
pthread_mutex_lock
pthread_mutexattr_init
pthread_mutexattr_settype
pthread_self
remove
T reset(T... args)
rmdir
sched_get_priority_min
sched_yield
typedef pthread_mutexattr_t
sysconf
system
time
times
utime
waitpid