Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions RealtimeWatchdog.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "RealtimeWatchdog"
s.version = "1.0.2"
s.version = "1.0.3"
s.summary = "A library for iOS audio which acts as a watchdog for unsafe activity on the audio thread."
s.description = <<-DESC
This library for iOS acts as a watchdog for activities on the Core Audio thread that are considered unsafe:
Expand All @@ -17,7 +17,7 @@ It won’t catch everything, and it won’t catch anything in Apple’s own syst
s.homepage = "https://github.com/TheAmazingAudioEngine/RealtimeWatchdog"
s.license = 'zlib'
s.author = { "Michael Tyson" => "[email protected]" }
s.source = { :git => "https://github.com/TheAmazingAudioEngine/RealtimeWatchdog.git", :tag => "1.0.2" }
s.source = { :git => "https://github.com/TheAmazingAudioEngine/RealtimeWatchdog.git", :tag => "1.0.3" }
s.ios.deployment_target = '9.0'
s.source_files = 'RealtimeWatchdog/*'
s.pod_target_xcconfig = { 'OTHER_CFLAGS' => '-fno-modules' }
Expand Down
16 changes: 12 additions & 4 deletions RealtimeWatchdog.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@
4C636E421D0D87AF005A380B /* AERealtimeWatchdog-simulator-x86_64.s in Sources */ = {isa = PBXBuildFile; fileRef = 4C636E3E1D0D87AF005A380B /* AERealtimeWatchdog-simulator-x86_64.s */; settings = {COMPILER_FLAGS = "-fno-modules"; }; };
4C636E431D0D87AF005A380B /* AERealtimeWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C636E401D0D87AF005A380B /* AERealtimeWatchdog.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
4C636E461D0D882E005A380B /* AERealtimeWatchdog.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C636E3F1D0D87AF005A380B /* AERealtimeWatchdog.h */; settings = {ATTRIBUTES = (Public, ); }; };
A40738DF271A3EC100C636FB /* AERealtimeWatchdogExt.m in Sources */ = {isa = PBXBuildFile; fileRef = A40738DE271A3EC100C636FB /* AERealtimeWatchdogExt.m */; };
A43D51A827212EDF00C931B1 /* AERealtimeWatchdogExt.h in Headers */ = {isa = PBXBuildFile; fileRef = A40738DD271A339600C636FB /* AERealtimeWatchdogExt.h */; settings = {ATTRIBUTES = (Public, ); }; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
4C636E311D0D878B005A380B /* libRealtimeWatchdog.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRealtimeWatchdog.a; sourceTree = BUILT_PRODUCTS_DIR; };
4C636E3D1D0D87AF005A380B /* AERealtimeWatchdog-arm64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = "AERealtimeWatchdog-arm64.s"; sourceTree = "<group>"; };
4C636E3E1D0D87AF005A380B /* AERealtimeWatchdog-simulator-x86_64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = "AERealtimeWatchdog-simulator-x86_64.s"; sourceTree = "<group>"; };
4C636E3F1D0D87AF005A380B /* AERealtimeWatchdog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AERealtimeWatchdog.h; sourceTree = "<group>"; };
4C636E401D0D87AF005A380B /* AERealtimeWatchdog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AERealtimeWatchdog.m; sourceTree = "<group>"; };
4C636E401D0D87AF005A380B /* AERealtimeWatchdog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AERealtimeWatchdog.m; sourceTree = "<group>"; usesTabs = 0; };
A40738DD271A339600C636FB /* AERealtimeWatchdogExt.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AERealtimeWatchdogExt.h; sourceTree = "<group>"; };
A40738DE271A3EC100C636FB /* AERealtimeWatchdogExt.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AERealtimeWatchdogExt.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -55,6 +59,8 @@
4C636E3E1D0D87AF005A380B /* AERealtimeWatchdog-simulator-x86_64.s */,
4C636E3F1D0D87AF005A380B /* AERealtimeWatchdog.h */,
4C636E401D0D87AF005A380B /* AERealtimeWatchdog.m */,
A40738DD271A339600C636FB /* AERealtimeWatchdogExt.h */,
A40738DE271A3EC100C636FB /* AERealtimeWatchdogExt.m */,
);
path = RealtimeWatchdog;
sourceTree = "<group>";
Expand All @@ -67,6 +73,7 @@
buildActionMask = 2147483647;
files = (
4C636E461D0D882E005A380B /* AERealtimeWatchdog.h in Headers */,
A43D51A827212EDF00C931B1 /* AERealtimeWatchdogExt.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -96,7 +103,7 @@
4C636E291D0D878B005A380B /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1250;
LastUpgradeCheck = 1600;
ORGANIZATIONNAME = "A Tasty Pixel";
TargetAttributes = {
4C636E301D0D878B005A380B = {
Expand Down Expand Up @@ -127,6 +134,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A40738DF271A3EC100C636FB /* AERealtimeWatchdogExt.m in Sources */,
4C636E421D0D87AF005A380B /* AERealtimeWatchdog-simulator-x86_64.s in Sources */,
4C636E431D0D87AF005A380B /* AERealtimeWatchdog.m in Sources */,
4C636E411D0D87AF005A380B /* AERealtimeWatchdog-arm64.s in Sources */,
Expand Down Expand Up @@ -185,7 +193,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
PUBLIC_HEADERS_FOLDER_PATH = "$(PROJECT_NAME)";
Expand Down Expand Up @@ -236,7 +244,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
PUBLIC_HEADERS_FOLDER_PATH = "$(PROJECT_NAME)";
SDKROOT = iphoneos;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
1 change: 0 additions & 1 deletion RealtimeWatchdog/AERealtimeWatchdog-simulator-x86_64.s
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
* limitations under the License.
*/


#include <TargetConditionals.h>
#include "AERealtimeWatchdog.h"
#if __x86_64__ && TARGET_OS_SIMULATOR && REALTIME_WATCHDOG_ENABLED
Expand Down
17 changes: 17 additions & 0 deletions RealtimeWatchdog/AERealtimeWatchdog.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,20 @@
#define REALTIME_WATCHDOG_ENABLED 1

#endif

#ifndef __ASSEMBLER__

#import "AERealtimeWatchdogExt.h"

/*!
* Pause monitoring until AERealtimeWatchdogResume called
*/
void AERealtimeWatchdogPause(void);

/*!
* Resume monitoring
*/
void AERealtimeWatchdogResume(void);

#endif

68 changes: 53 additions & 15 deletions RealtimeWatchdog/AERealtimeWatchdog.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,23 @@
//

#import "AERealtimeWatchdog.h"
#import <Foundation/Foundation.h>
#import <objc/runtime.h>

static BOOL __paused = NO;

void AERealtimeWatchdogPause(void) {
__paused = YES;
}

void AERealtimeWatchdogResume(void) {
__paused = NO;
}

#ifdef REALTIME_WATCHDOG_ENABLED

#import <dlfcn.h>
#import <stdio.h>
#import <objc/runtime.h>
#import <pthread.h>
#import <string.h>
#include <sys/socket.h>
Expand All @@ -40,8 +52,6 @@
//#define REPORT_EVERY_INFRACTION




static void AERealtimeWatchdogUnsafeActivityWarning(const char * activity) {
#ifndef REPORT_EVERY_INFRACTION
static BOOL once = NO;
Expand All @@ -57,6 +67,25 @@ static void AERealtimeWatchdogUnsafeActivityWarning(const char * activity) {
#endif
}

#if TARGET_OS_MACCATALYST
char kAERealtimeWatchdogThreadName[64] = "com.apple.audio.IOThread.client";
#else
char kAERealtimeWatchdogThreadName[64] = "AURemoteIO::IOThread";
#endif

// This function will be called before main() to query the process info for the current platform
void InitRealtimeThreadName(void) __attribute__((constructor));
void InitRealtimeThreadName(void) {
if (@available(iOS 14.0, *)) {
if (NSProcessInfo.processInfo.isiOSAppOnMac) {
strncpy(kAERealtimeWatchdogThreadName, "com.apple.audio.IOThread.client", sizeof(kAERealtimeWatchdogThreadName));
}
}
}



pthread_t sAERealtimeThread = 0;

BOOL AERealtimeWatchdogIsOnRealtimeThread(void) {
pthread_t thread = pthread_self();
Expand All @@ -67,9 +96,13 @@ BOOL AERealtimeWatchdogIsOnRealtimeThread(void) {
if ( pthread_getschedparam(thread, &policy, &param) == 0 && param.sched_priority >= sched_get_priority_max(policy) ) {
return YES;
}
#elif defined(USE_WATCHDOG_REGISTRATION_FUNCTIONS) // Trying a thread registration test
if (sAERealtimeThread == thread) {
return YES;
}
#else
char name[21];
if ( pthread_getname_np(thread, name, sizeof(name)) == 0 && !strcmp(name, "AURemoteIO::IOThread") ) {
char name[64];
if ( pthread_getname_np(thread, name, sizeof(name)) == 0 && !strcmp(name, kAERealtimeWatchdogThreadName) ) {
return YES;
}
#endif
Expand All @@ -78,9 +111,6 @@ BOOL AERealtimeWatchdogIsOnRealtimeThread(void) {
}





#pragma mark - Overrides

// Signatures for the functions we'll override
Expand All @@ -94,7 +124,9 @@ BOOL AERealtimeWatchdogIsOnRealtimeThread(void) {
typedef int (*objc_sync_enter_t)(id obj);
typedef id (*objc_storeStrong_t)(id *object, id value);
typedef id (*objc_loadWeak_t)(id *object);
typedef id (*objc_loadWeakRetained_t)(id *object);
typedef id (*objc_storeWeak_t)(id *object, id value);
typedef id (*objc_retainAutoreleasedReturnValue_t)(id *object, id value);
typedef id (*object_getIvar_t)(id object, Ivar ivar);
typedef id (*objc_msgSend_t)(void);
typedef ssize_t (*send_t)(int socket, const void *buffer, size_t length, int flags);
Expand Down Expand Up @@ -134,7 +166,6 @@ typedef ssize_t (*recvfrom_t)(int socket, void *restrict buffer, size_t length,

typedef dispatch_semaphore_t (*dispatch_semaphore_create_t)(long value);
typedef long (*dispatch_semaphore_wait_t)(dispatch_semaphore_t dsema, dispatch_time_t timeout);
typedef long (*dispatch_semaphore_signal_t)(dispatch_semaphore_t dsema);

// Overrides

Expand All @@ -144,7 +175,7 @@ typedef ssize_t (*recvfrom_t)(int socket, void *restrict buffer, size_t length,
dispatch_once(&onceToken, ^{ \
funcptr = (name##_t) dlsym(RTLD_NEXT, #name); \
}); \
if ( AERealtimeWatchdogIsOnRealtimeThread() ) AERealtimeWatchdogUnsafeActivityWarning(msg);
if ( !__paused && AERealtimeWatchdogIsOnRealtimeThread() ) AERealtimeWatchdogUnsafeActivityWarning(msg);

#define CHECK_FUNCTION(name) CHECK_FUNCTION_MSG(name, #name)

Expand Down Expand Up @@ -200,12 +231,24 @@ id objc_loadWeak(id * object) {
return funcptr(object);
}

id objc_loadWeakRetained(id * object);
id objc_loadWeakRetained(id * object) {
CHECK_FUNCTION_MSG(objc_loadWeakRetained, "weak load");
return funcptr(object);
}

id objc_storeWeak(id * object, id value);
id objc_storeWeak(id * object, id value) {
CHECK_FUNCTION_MSG(objc_storeWeak, "weak store");
return funcptr(object,value);
}

id objc_retainAutoreleasedReturnValue(id * object, id value);
id objc_retainAutoreleasedReturnValue(id * object, id value) {
CHECK_FUNCTION_MSG(objc_retainAutoreleasedReturnValue, "retain autoreleased return value");
return funcptr(object,value);
}

id object_getIvar(id object, Ivar value);
id object_getIvar(id object, Ivar value) {
CHECK_FUNCTION_MSG(object_getIvar, "ivar fetch");
Expand Down Expand Up @@ -383,9 +426,4 @@ long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout
return funcptr(dsema, timeout);
}

long dispatch_semaphore_signal(dispatch_semaphore_t dsema) {
CHECK_FUNCTION(dispatch_semaphore_signal);
return funcptr(dsema);
}

#endif
55 changes: 55 additions & 0 deletions RealtimeWatchdog/AERealtimeWatchdogExt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//
// AERealtimeWatchdogMonitor.h
// TheAmazingAudioEngine
//
// Created by Michael Tyson on 12/06/2016.
// Idea by Taylor Holliday
// Copyright © 2016 A Tasty Pixel. All rights reserved.
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//

// Uncomment the following to use the thread registration functions. You must call
// AERealtimeWatchdogStartMonitoring and AERealtimeWatchdogStopMonitoring from the realtime thread.
//#define USE_WATCHDOG_REGISTRATION_FUNCTIONS 1


#ifndef __ASSEMBLER__
#if defined(REALTIME_WATCHDOG_ENABLED) && defined(USE_WATCHDOG_REGISTRATION_FUNCTIONS)

#if defined(__cplusplus)
extern "C" {
#endif
// Call this at the very top of the playback and record callbacks
void AERealtimeWatchdogStartMonitoring(void);
// Call this at the very end of the playback and record callbacks
void AERealtimeWatchdogStopMonitoring(void);
#if defined(__cplusplus)
}
#endif

#else // !REALTIME_WATCHDOG_ENABLED

// Stubbed out for release
static inline void AERealtimeWatchdogStartMonitoring(void) {};
static inline void AERealtimeWatchdogStopMonitoring(void) {};

#endif // REALTIME_WATCHDOG_ENABLED
#endif // REALTIME_WATCHDOG_INCLUDED_BY_ASM

65 changes: 65 additions & 0 deletions RealtimeWatchdog/AERealtimeWatchdogExt.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//
// AERealtimeWatchdogMonitor.h
// TheAmazingAudioEngine
//
// Created by Michael Tyson on 12/06/2016.
// Idea by Taylor Holliday
// Copyright © 2016 A Tasty Pixel. All rights reserved.
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//

#import <pthread.h>
#import <string.h>
#import <stdio.h>

#import "AERealtimeWatchdog.h"

#if defined(REALTIME_WATCHDOG_ENABLED) && defined(USE_WATCHDOG_REGISTRATION_FUNCTIONS)


extern pthread_t sAERealtimeThread;
extern char kAERealtimeWatchdogThreadName[64];

// Call this at the very top of the playback and record callbacks
void AERealtimeWatchdogStartMonitoring(void) {
pthread_t thread = pthread_self();

// All we really need is to assign sAERealtimeThread, but do a few sanity checks
char name[64];
if ( pthread_getname_np(thread, name, sizeof(name)) == 0 && !strcmp(name, kAERealtimeWatchdogThreadName) ) {
if (sAERealtimeThread != NULL) {
printf("AERealtimeWatchdog: Unmatched start/stop!\n");
}
sAERealtimeThread = thread;
} else {
printf("AERealtimeWatchdog: %s not called from the realtime thread!\n", __FUNCTION__);
sAERealtimeThread = NULL;
}
}

// Call this at the very end of the playback and record callbacks
void AERealtimeWatchdogStopMonitoring(void) {
if (sAERealtimeThread == NULL) {
printf("AERealtimeWatchdog: Unmatched start/stop!\n");
}
sAERealtimeThread = NULL;
}

#endif