aboutsummaryrefslogtreecommitdiffstats
path: root/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m
diff options
context:
space:
mode:
Diffstat (limited to 'Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m')
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m61
1 files changed, 61 insertions, 0 deletions
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m
index 800157ca..d42b82e6 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m
@@ -36,6 +36,9 @@
#include <pthread.h>
#include <SystemConfiguration/SCNetworkReachability.h>
+// Thread flag constant
+static pthread_key_t mySQLThreadInitFlagKey;
+static void *mySQLThreadFlag;
#pragma mark Class constants
@@ -76,6 +79,24 @@ const char *SPMySQLSSLPermissibleCiphers = "DHE-RSA-AES256-SHA:AES256-SHA:DHE-RS
#pragma mark Initialisation and teardown
/**
+ * In the one-off class initialisation, set up MySQL as necessary
+ */
++ (void)initialize
+{
+
+ // Set up a pthread thread-specific data key to be used across all classes and threads
+ pthread_key_create(&mySQLThreadInitFlagKey, NULL);
+ mySQLThreadFlag = malloc(1);
+
+ // MySQL requires mysql_library_init() to be called before any other MySQL
+ // functions are used; although mysql_init() will call it automatically, it
+ // won't do so in a thread-safe manner, so setting it up first is safer.
+ // No arguments are required.
+ // Note that this will install MySQL's SIGPIPE handler.
+ mysql_library_init(0, NULL, NULL);
+}
+
+/**
* Initialise the SPMySQLConnection object, setting up class defaults.
*
* Typically initialisation would be followed by setting the connection details
@@ -631,6 +652,13 @@ const char *SPMySQLSSLPermissibleCiphers = "DHE-RSA-AES256-SHA:AES256-SHA:DHE-RS
MYSQL *theConnection = mysql_init(NULL);
if (!theConnection) return NULL;
+ // Calling mysql_init will have automatically installed per-thread variables if necessary,
+ // so track their installation for removal and to avoid recreating again.
+ if (!pthread_getspecific(mySQLThreadInitFlagKey)) {
+ pthread_setspecific(mySQLThreadInitFlagKey, &mySQLThreadFlag);
+ [(NSNotificationCenter *)[NSNotificationCenter defaultCenter] addObserver:[self class] selector:@selector(_removeThreadVariables:) name:NSThreadWillExitNotification object:[NSThread currentThread]];
+ }
+
// Disable automatic reconnection, as it's handled in-framework to preserve
// options, encodings and connection state.
my_bool falseMyBool = FALSE;
@@ -835,4 +863,37 @@ const char *SPMySQLSSLPermissibleCiphers = "DHE-RSA-AES256-SHA:AES256-SHA:DHE-RS
// Otherwise check the connection
return [self checkConnection];
}
+
+/**
+ * Ensure that the thread this method is called on has been registered for
+ * use with MySQL. MySQL requires thread-specific variables for safe
+ * execution.
+ */
+- (void)_validateThreadSetup
+{
+
+ // Check to see whether the handler has already been installed
+ if (pthread_getspecific(mySQLThreadInitFlagKey)) return;
+
+ // If not, install it
+ mysql_thread_init();
+
+ // Mark the thread to avoid multiple installs
+ pthread_setspecific(mySQLThreadInitFlagKey, &mySQLThreadFlag);
+
+ // Set up the notification handler to deregister it
+ [(NSNotificationCenter *)[NSNotificationCenter defaultCenter] addObserver:[self class] selector:@selector(_removeThreadVariables:) name:NSThreadWillExitNotification object:[NSThread currentThread]];
+}
+
+/**
+ * Remove the MySQL variables and handlers from each closing thread which
+ * has had them installed to avoid memory leaks.
+ * This is a class method for easy global tracking; it will be called on the appropriate
+ * thread automatically.
+ */
++ (void)_removeThreadVariables:(NSNotification *)aNotification
+{
+ mysql_thread_end();
+}
+
@end