gnome-keyring r1411 - in trunk: . gp11 gp11/tests



Author: nnielsen
Date: Sat Dec 27 18:29:23 2008
New Revision: 1411
URL: http://svn.gnome.org/viewvc/gnome-keyring?rev=1411&view=rev

Log:
	* gp11/gp11.h:
	* gp11/gp11-call.c:
	* gp11/gp11-marshal.list:
	* gp11/gp11-misc.c:
	* gp11/gp11-module.c:
	* gp11/gp11-object.c:
	* gp11/gp11-session.c:
	* gp11/gp11-slot.c:
	* gp11/tests/unit-test-gp11-module.c:
	* gp11/tests/unit-test-gp11-object.c:
	* gp11/tests/unit-test-gp11-session.c: Add basic thread-safety.


Modified:
   trunk/ChangeLog
   trunk/gp11/gp11-call.c
   trunk/gp11/gp11-marshal.list
   trunk/gp11/gp11-misc.c
   trunk/gp11/gp11-module.c
   trunk/gp11/gp11-object.c
   trunk/gp11/gp11-session.c
   trunk/gp11/gp11-slot.c
   trunk/gp11/gp11.h
   trunk/gp11/tests/unit-test-gp11-module.c
   trunk/gp11/tests/unit-test-gp11-object.c
   trunk/gp11/tests/unit-test-gp11-session.c

Modified: trunk/gp11/gp11-call.c
==============================================================================
--- trunk/gp11/gp11-call.c	(original)
+++ trunk/gp11/gp11-call.c	Sat Dec 27 18:29:23 2008
@@ -33,6 +33,7 @@
 
 struct _GP11Call {
 	GObject parent;
+	GP11Module *module;
 	
 	/* For making the call */
 	GP11CallFunc func;
@@ -131,6 +132,8 @@
 static void 
 process_result (GP11Call *call, gpointer unused)
 {
+	GP11Slot *slot;
+	
 	/* Double check a few things */
 	g_assert (GP11_IS_CALL (call));
 	
@@ -147,8 +150,10 @@
 	if (call->rv == CKR_USER_NOT_LOGGED_IN && GP11_IS_SESSION (call->object)) {
 		g_free (call->password);
 		call->password = NULL;
-		call->do_login = _gp11_slot_token_authentication (GP11_SESSION (call->object)->slot, 
-		                                                  &call->password);
+		slot = gp11_session_get_slot (GP11_SESSION (call->object));
+		g_assert (GP11_IS_SLOT (slot));
+		call->do_login = _gp11_slot_token_authentication (slot, &call->password);
+		g_object_unref (slot);
 	}
 	
 	/* If we're supposed to do a login, then queue this call again */
@@ -238,6 +243,10 @@
 _gp11_call_finalize (GObject *obj)
 {
 	GP11Call *call = GP11_CALL (obj);
+	
+	if (call->module)
+		g_object_unref (call->module);
+	call->module = NULL;
 
 	if (call->object)
 		g_object_unref (call->object);
@@ -395,6 +404,7 @@
 	GP11Arguments *args = (GP11Arguments*)data;
 	gchar *password = NULL;
 	GP11Module *module = NULL;
+	GP11Slot *slot; 
 	CK_ULONG pin_len;
 	CK_RV rv;
 	
@@ -404,9 +414,10 @@
 	
 	g_object_get (object, "module", &module, "handle", &args->handle, NULL);
 	g_assert (GP11_IS_MODULE (module));
-	
-	args->pkcs11 = module->funcs;
-	g_object_unref (module);
+
+	/* We now hold a reference to module until below */
+	args->pkcs11 = gp11_module_get_function_list (module);
+	g_assert (args->pkcs11);
 	
 	rv = perform_call ((GP11CallFunc)func, cancellable, args);
 		
@@ -417,20 +428,23 @@
 	if (rv == CKR_USER_NOT_LOGGED_IN && GP11_IS_SESSION (object)) {
 		
 		do {
-			if (!_gp11_slot_token_authentication (GP11_SESSION (object)->slot, 
-			                                      &password)) {
+			slot = gp11_session_get_slot (GP11_SESSION (object));
+			if (!_gp11_slot_token_authentication (slot, &password)) {
 				rv = CKR_USER_NOT_LOGGED_IN;
 			} else {
 				pin_len = password ? strlen (password) : 0; 
 				rv = (args->pkcs11->C_Login) (args->handle, CKU_USER, 
 				                              (CK_UTF8CHAR_PTR)password, pin_len);
 			}
+			g_object_unref (slot);
 		} while (rv == CKR_PIN_INCORRECT);
 
 		/* If we logged in successfully then try again */
 		if (rv == CKR_OK)
 			rv = perform_call ((GP11CallFunc)func, cancellable, args);
 	}
+	
+	g_object_unref (module);
 
 	if (rv == CKR_OK)
 		return TRUE;
@@ -477,15 +491,18 @@
 void
 _gp11_call_async_object (GP11Call *call, gpointer object)
 {
-	GP11Module *module;
-	
 	g_assert (GP11_IS_CALL (call));
 	g_assert (call->args);
 	
-	g_object_get (object, "module", &module, "handle", &call->args->handle, NULL);
-	g_assert (GP11_IS_MODULE (module));
-	call->args->pkcs11 = module->funcs;
-	g_object_unref (module);
+	if (call->module)
+		g_object_unref (call->module);
+	call->module = NULL;
+	
+	g_object_get (object, "module", &call->module, "handle", &call->args->handle, NULL);
+	g_assert (GP11_IS_MODULE (call->module));
+	call->args->pkcs11 = gp11_module_get_function_list (call->module);
+	
+	/* We now hold a reference on module until finalize */
 }
 
 GP11Call*

Modified: trunk/gp11/gp11-marshal.list
==============================================================================
--- trunk/gp11/gp11-marshal.list	(original)
+++ trunk/gp11/gp11-marshal.list	Sat Dec 27 18:29:23 2008
@@ -1,2 +1,3 @@
 BOOLEAN:POINTER
 BOOLEAN:OBJECT,POINTER
+BOOLEAN:ULONG

Modified: trunk/gp11/gp11-misc.c
==============================================================================
--- trunk/gp11/gp11-misc.c	(original)
+++ trunk/gp11/gp11-misc.c	Sat Dec 27 18:29:23 2008
@@ -38,8 +38,13 @@
 gp11_get_error_quark (void)
 {
 	static GQuark domain = 0;
-	if (domain == 0)
+	static volatile gsize quark_inited = 0;
+	
+	if (g_once_init_enter (&quark_inited)) {
 		domain = g_quark_from_static_string ("gp11-error");
+		g_once_init_leave (&quark_inited, 1);
+	}
+	
 	return domain;
 }
 

Modified: trunk/gp11/gp11-module.c
==============================================================================
--- trunk/gp11/gp11-module.c	(original)
+++ trunk/gp11/gp11-module.c	Sat Dec 27 18:29:23 2008
@@ -27,18 +27,35 @@
 
 #include <string.h>
 
+/*
+ * MT safe 
+ * 
+ * The only thing that can change after object initialization in
+ * a GP11Module is the finalized flag, which can be set
+ * to 1 in dispose.
+ */
+
 enum {
 	PROP_0,
-	PROP_MODULE_PATH
+	PROP_PATH,
+	PROP_FUNCTION_LIST
 };
 
-typedef struct _GP11ModulePrivate {
+typedef struct _GP11ModuleData {
 	GModule *module;
+	gchar *path;
+	gint finalized;
+	CK_FUNCTION_LIST_PTR funcs;
 	CK_C_INITIALIZE_ARGS init_args;
+} GP11ModuleData;
+
+typedef struct _GP11ModulePrivate {
+	GP11ModuleData data;
+	/* Add future mutex and non-MT-safe data here */
 } GP11ModulePrivate;
 
-#define GP11_MODULE_GET_PRIVATE(o) \
-      (G_TYPE_INSTANCE_GET_PRIVATE((o), GP11_TYPE_MODULE, GP11ModulePrivate))
+#define GP11_MODULE_GET_DATA(o) \
+      (G_TYPE_INSTANCE_GET_PRIVATE((o), GP11_TYPE_MODULE, GP11ModuleData))
 
 G_DEFINE_TYPE (GP11Module, gp11_module, G_TYPE_OBJECT);
 
@@ -94,7 +111,7 @@
  */
 
 static void
-gp11_module_init (GP11Module *module)
+gp11_module_init (GP11Module *self)
 {
 	
 }
@@ -103,11 +120,14 @@
 gp11_module_get_property (GObject *obj, guint prop_id, GValue *value, 
                           GParamSpec *pspec)
 {
-	GP11Module *module = GP11_MODULE (obj);
+	GP11Module *self = GP11_MODULE (obj);
 
 	switch (prop_id) {
-	case PROP_MODULE_PATH:
-		g_value_set_string (value, module->path);
+	case PROP_PATH:
+		g_value_set_string (value, gp11_module_get_path (self));
+		break;
+	case PROP_FUNCTION_LIST:
+		g_value_set_pointer (value, gp11_module_get_function_list (self));
 		break;
 	}
 }
@@ -116,14 +136,14 @@
 gp11_module_set_property (GObject *obj, guint prop_id, const GValue *value, 
                           GParamSpec *pspec)
 {
-	GP11ModulePrivate *pv = GP11_MODULE_GET_PRIVATE (obj);
-	GP11Module *module = GP11_MODULE (obj);
+	GP11ModuleData *data = GP11_MODULE_GET_DATA (obj);
 
+	/* Only allowed during initialization */
 	switch (prop_id) {
-	case PROP_MODULE_PATH:
-		g_return_if_fail (!pv->module);
-		module->path = g_value_dup_string (value);
-		g_return_if_fail (module->path);
+	case PROP_PATH:
+		g_return_if_fail (!data->path);
+		data->path = g_value_dup_string (value);
+		g_return_if_fail (data->path);
 		break;
 	}
 }
@@ -131,36 +151,39 @@
 static void
 gp11_module_dispose (GObject *obj)
 {
-	GP11Module *module = GP11_MODULE (obj);
+	GP11ModuleData *data = GP11_MODULE_GET_DATA (obj);
+	gint finalized = g_atomic_int_get (&data->finalized);
 	CK_RV rv;
-	
-	if (module->funcs) {
-		rv = (module->funcs->C_Finalize) (NULL);
+
+	/* Must be careful when accessing funcs */
+	if (data->funcs && !finalized && 
+	    g_atomic_int_compare_and_exchange (&data->finalized, finalized, 1)) {
+		rv = (data->funcs->C_Finalize) (NULL);
 		if (rv != CKR_OK) {
 			g_warning ("C_Finalize on module '%s' failed: %s", 
-			           module->path, gp11_message_from_rv (rv));
+			           data->path, gp11_message_from_rv (rv));
 		}
-		module->funcs = NULL;
 	}
+	
+	G_OBJECT_CLASS (gp11_module_parent_class)->dispose (obj);
 }
 
 static void
 gp11_module_finalize (GObject *obj)
 {
-	GP11ModulePrivate *pv = GP11_MODULE_GET_PRIVATE (obj);
-	GP11Module *module = GP11_MODULE (obj);
+	GP11ModuleData *data = GP11_MODULE_GET_DATA (obj);
 
-	g_assert (module->funcs == NULL);
+	data->funcs = NULL;
 	
-	if (pv->module) {
-		if (!g_module_close (pv->module))
+	if (data->module) {
+		if (!g_module_close (data->module))
 			g_warning ("failed to close the pkcs11 module: %s", 
 			           g_module_error ());
-		pv->module = NULL;
+		data->module = NULL;
 	}
 	
-	g_free (module->path);
-	module->path = NULL;
+	g_free (data->path);
+	data->path = NULL;
 	
 	G_OBJECT_CLASS (gp11_module_parent_class)->finalize (obj);
 }
@@ -177,10 +200,14 @@
 	gobject_class->dispose = gp11_module_dispose;
 	gobject_class->finalize = gp11_module_finalize;
 	
-	g_object_class_install_property (gobject_class, PROP_MODULE_PATH,
-		g_param_spec_string ("module-path", "Module Path", "Path to the PKCS11 Module",
+	g_object_class_install_property (gobject_class, PROP_PATH,
+		g_param_spec_string ("path", "Module Path", "Path to the PKCS11 Module",
 		                     NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
+	g_object_class_install_property (gobject_class, PROP_FUNCTION_LIST,
+		g_param_spec_pointer ("function-list", "Function List", "PKCS11 Function List",
+		                      G_PARAM_READABLE));
+
 	g_type_class_add_private (gobject_class, sizeof (GP11ModulePrivate));
 }
 
@@ -218,19 +245,19 @@
 gp11_module_initialize (const gchar *path, gpointer reserved, GError **err)
 {
 	CK_C_GetFunctionList get_function_list;
-	GP11ModulePrivate *pv;
+	GP11ModuleData *data;
 	GP11Module *mod;
 	CK_RV rv;
 	
 	g_return_val_if_fail (path != NULL, NULL);
 	g_return_val_if_fail (!err || !*err, NULL);
 	
-	mod = g_object_new (GP11_TYPE_MODULE, "module-path", path, NULL);
-	pv = GP11_MODULE_GET_PRIVATE (mod);
+	mod = g_object_new (GP11_TYPE_MODULE, "path", path, NULL);
+	data = GP11_MODULE_GET_DATA (mod);
 	
 	/* Load the actual module */
-	pv->module = g_module_open (path, 0);
-	if (!pv->module) {
+	data->module = g_module_open (path, 0);
+	if (!data->module) {
 		g_set_error (err, GP11_ERROR, (int)CKR_GP11_MODULE_PROBLEM,
 		             "Error loading pkcs11 module: %s", g_module_error ());
 		g_object_unref (mod);
@@ -238,7 +265,7 @@
 	}
 	
 	/* Get the entry point */
-	if (!g_module_symbol (pv->module, "C_GetFunctionList", (void**)&get_function_list)) {
+	if (!g_module_symbol (data->module, "C_GetFunctionList", (void**)&get_function_list)) {
 		g_set_error (err, GP11_ERROR, (int)CKR_GP11_MODULE_PROBLEM,
 		             "Invalid pkcs11 module: %s", g_module_error ());
 		g_object_unref (mod);
@@ -246,7 +273,7 @@
 	}
 	
 	/* Get the function list */
-	rv = (get_function_list) (&mod->funcs);
+	rv = (get_function_list) (&data->funcs);
 	if (rv != CKR_OK) {
 		g_set_error (err, GP11_ERROR, rv, "Couldn't get pkcs11 function list: %s",
 		             gp11_message_from_rv (rv));
@@ -254,26 +281,16 @@
 		return NULL;
 	}
 	
-	/* Make sure we have a compatible version */
-	if (mod->funcs->version.major != CRYPTOKI_VERSION_MAJOR) {
-		g_set_error (err, GP11_ERROR, (int)CKR_GP11_MODULE_PROBLEM,
-		             "Incompatible version of pkcs11 module: %d.%d",
-		             (int)mod->funcs->version.major,
-		             (int)mod->funcs->version.minor);
-		g_object_unref (mod);
-		return NULL;
-	}
-	
-	memset (&pv->init_args, 0, sizeof (pv->init_args));
-	pv->init_args.flags = CKF_OS_LOCKING_OK;
-	pv->init_args.CreateMutex = create_mutex;
-	pv->init_args.DestroyMutex = destroy_mutex;
-	pv->init_args.LockMutex = lock_mutex;
-	pv->init_args.UnlockMutex = unlock_mutex;
-	pv->init_args.pReserved = reserved;
+	memset (&data->init_args, 0, sizeof (data->init_args));
+	data->init_args.flags = CKF_OS_LOCKING_OK;
+	data->init_args.CreateMutex = create_mutex;
+	data->init_args.DestroyMutex = destroy_mutex;
+	data->init_args.LockMutex = lock_mutex;
+	data->init_args.UnlockMutex = unlock_mutex;
+	data->init_args.pReserved = reserved;
 	
 	/* Now initialize the module */
-	rv = (mod->funcs->C_Initialize) (&pv->init_args);
+	rv = (data->funcs->C_Initialize) (&data->init_args);
 	if (rv != CKR_OK) {
 		g_set_error (err, GP11_ERROR, rv, "Couldn't initialize module: %s",
 		             gp11_message_from_rv (rv));
@@ -286,24 +303,25 @@
 
 /**
  * gp11_module_get_info:
- * @module: The module to get info for.
+ * @self: The module to get info for.
  * 
  * Get the info about a PKCS#11 module. 
  * 
  * Return value: The module info. Release this with gp11_module_info_free().
  **/
 GP11ModuleInfo*
-gp11_module_get_info (GP11Module *module)
+gp11_module_get_info (GP11Module *self)
 {
+	GP11ModuleData *data = GP11_MODULE_GET_DATA (self);
 	GP11ModuleInfo *modinfo;
 	CK_INFO info;
 	CK_RV rv;
 	
-	g_return_val_if_fail (GP11_IS_MODULE (module), NULL);
-	g_return_val_if_fail (module->funcs, NULL);
+	g_return_val_if_fail (GP11_IS_MODULE (self), NULL);
+	g_return_val_if_fail (data->funcs, NULL);
 	
 	memset (&info, 0, sizeof (info));
-	rv = (module->funcs->C_GetInfo (&info));
+	rv = (data->funcs->C_GetInfo (&info));
 	if (rv != CKR_OK) {
 		g_warning ("couldn't get module info: %s", gp11_message_from_rv (rv));
 		return NULL;
@@ -325,7 +343,7 @@
 
 /**
  * gp11_module_get_slots:
- * @module: The module for which to get the slots.
+ * @self: The module for which to get the slots.
  * @token_present: Whether to limit only to slots with a token present.
  * 
  * Get the GP11Slot objects for a given module. 
@@ -333,17 +351,18 @@
  * Return value: The possibly empty list of slots. Release this with gp11_list_unref_free().
  */
 GList*
-gp11_module_get_slots (GP11Module *module, gboolean token_present)
+gp11_module_get_slots (GP11Module *self, gboolean token_present)
 {
+	GP11ModuleData *data = GP11_MODULE_GET_DATA (self);
 	CK_SLOT_ID_PTR slot_list;
 	CK_ULONG count, i;
 	GList *result;
 	CK_RV rv;
 	
-	g_return_val_if_fail (GP11_IS_MODULE (module), NULL);
-	g_return_val_if_fail (module->funcs, NULL);
+	g_return_val_if_fail (GP11_IS_MODULE (self), NULL);
+	g_return_val_if_fail (data->funcs, NULL);
 
-	rv = (module->funcs->C_GetSlotList) (token_present ? CK_TRUE : CK_FALSE, NULL, &count);
+	rv = (data->funcs->C_GetSlotList) (token_present ? CK_TRUE : CK_FALSE, NULL, &count);
 	if (rv != CKR_OK) {
 		g_warning ("couldn't get slot count: %s", gp11_message_from_rv (rv));
 		return NULL;
@@ -353,7 +372,7 @@
 		return NULL;
 	
 	slot_list = g_new (CK_SLOT_ID, count);
-	rv = (module->funcs->C_GetSlotList) (token_present ? CK_TRUE : CK_FALSE, slot_list, &count);
+	rv = (data->funcs->C_GetSlotList) (token_present ? CK_TRUE : CK_FALSE, slot_list, &count);
 	if (rv != CKR_OK) {
 		g_warning ("couldn't get slot list: %s", gp11_message_from_rv (rv));
 		g_free (slot_list);
@@ -362,13 +381,44 @@
 	
 	result = NULL;
 	for (i = 0; i < count; ++i) {
-		/* TODO: Should we be looking these up somewhere? */
 		result = g_list_prepend (result, g_object_new (GP11_TYPE_SLOT, 
 		                                               "handle", slot_list[i],
-		                                               "module", module, NULL));
+		                                               "module", self, NULL));
 	}
 	
 	g_free (slot_list);
 	return g_list_reverse (result);
 }
 
+/**
+ * gp11_module_get_path:
+ * @self: The module for which to get the path.
+ * 
+ * Get the file path of this module. This may not be an absolute path, and 
+ * usually reflects the path passed to gp11_module_initialize().
+ * 
+ * Return value: The path, do not modify or free this value. 
+ **/
+const gchar*
+gp11_module_get_path (GP11Module *self)
+{
+	GP11ModuleData *data = GP11_MODULE_GET_DATA (self);
+	g_return_val_if_fail (GP11_IS_MODULE (self), NULL);
+	return data->path;
+}
+
+/**
+ * gp11_module_get_function_list:
+ * @self: The module for which to get the function list.
+ * 
+ * Get the PKCS#11 function list for the module.
+ * 
+ * Return value: The function list, do not modify this structure. 
+ **/
+CK_FUNCTION_LIST_PTR
+gp11_module_get_function_list (GP11Module *self)
+{
+	GP11ModuleData *data = GP11_MODULE_GET_DATA (self);
+	g_return_val_if_fail (GP11_IS_MODULE (self), NULL);
+	return data->funcs;	
+}

Modified: trunk/gp11/gp11-object.c
==============================================================================
--- trunk/gp11/gp11-object.c	(original)
+++ trunk/gp11/gp11-object.c	Sat Dec 27 18:29:23 2008
@@ -28,6 +28,12 @@
 
 #include <string.h>
 
+/*
+ * MT safe -- Nothing in GP11ObjectData changes between 
+ * init and finalize. All GP11ObjectPrivate access between init
+ * and finalize is locked.
+ */
+
 enum {
 	PROP_0,
 	PROP_MODULE,
@@ -36,6 +42,21 @@
 	PROP_SESSION
 };
 
+typedef struct _GP11ObjectData {
+	GP11Module *module;
+	GP11Slot *slot;
+	CK_OBJECT_HANDLE handle;
+} GP11ObjectData;
+
+typedef struct _GP11ObjectPrivate {
+	GP11ObjectData data;
+	GStaticMutex mutex;
+	GP11Session *session;
+} GP11ObjectPrivate;
+
+#define GP11_OBJECT_GET_DATA(o) \
+      (G_TYPE_INSTANCE_GET_PRIVATE((o), GP11_TYPE_OBJECT, GP11ObjectData))
+
 G_DEFINE_TYPE (GP11Object, gp11_object, G_TYPE_OBJECT);
 
 /* ----------------------------------------------------------------------------
@@ -80,26 +101,37 @@
 }
 
 static void
-require_session_async (GP11Object *object, GP11Call *call, 
+require_session_async (GP11Object *self, GP11Call *call, 
                        gulong flags, GCancellable *cancellable)
 {
-	g_assert (GP11_IS_OBJECT (object));
+	GP11ObjectData *data = GP11_OBJECT_GET_DATA (self);
+	GP11Session *session;
+	
+	g_assert (GP11_IS_OBJECT (self));
+	
+	session = gp11_object_get_session (self);
+	if (session) {
+		run_call_with_session (call, session);
+		g_object_unref (session);
+	} else {
+		gp11_slot_open_session_async (data->slot, flags, cancellable, opened_session, call);
+	}
 	
-	if (object->session)
-		run_call_with_session (call, object->session);
-	else
-		gp11_slot_open_session_async (object->slot, flags, cancellable, opened_session, call);
 }
 
 static GP11Session*
-require_session_sync (GP11Object *object, gulong flags, GError **err)
+require_session_sync (GP11Object *self, gulong flags, GError **err)
 {
-	g_assert (GP11_IS_OBJECT (object));
+	GP11ObjectData *data = GP11_OBJECT_GET_DATA (self);
+	GP11Session *session;
+	
+	g_assert (GP11_IS_OBJECT (self));
 
-	if (object->session) 
-		return g_object_ref (object->session);
+	session = gp11_object_get_session (self);
+	if (session)
+		return session;
 	
-	return gp11_slot_open_session (object->slot, flags, err);
+	return gp11_slot_open_session (data->slot, flags, err);
 }
 
 /* ----------------------------------------------------------------------------
@@ -107,29 +139,30 @@
  */
 
 static void
-gp11_object_init (GP11Object *object)
+gp11_object_init (GP11Object *self)
 {
-	
+	GP11ObjectPrivate *pv = (G_TYPE_INSTANCE_GET_PRIVATE(self, GP11_TYPE_OBJECT, GP11ObjectPrivate));
+	g_static_mutex_init (&pv->mutex);
 }
 
 static void
 gp11_object_get_property (GObject *obj, guint prop_id, GValue *value, 
-                           GParamSpec *pspec)
+                          GParamSpec *pspec)
 {
-	GP11Object *object = GP11_OBJECT (obj);
+	GP11Object *self = GP11_OBJECT (obj);
 
 	switch (prop_id) {
 	case PROP_MODULE:
-		g_value_set_object (value, object->module);
+		g_value_take_object (value, gp11_object_get_module (self));
 		break;
 	case PROP_SLOT:
-		g_value_set_object (value, object->slot);
+		g_value_take_object (value, gp11_object_get_slot (self));
 		break;
 	case PROP_SESSION:
-		g_value_set_object (value, object->session);
+		g_value_take_object (value, gp11_object_get_session (self));
 		break;
 	case PROP_HANDLE:
-		g_value_set_uint (value, object->handle);
+		g_value_set_ulong (value, gp11_object_get_handle (self));
 		break;
 	}
 }
@@ -138,61 +171,55 @@
 gp11_object_set_property (GObject *obj, guint prop_id, const GValue *value, 
                           GParamSpec *pspec)
 {
-	GP11Object *object = GP11_OBJECT (obj);
+	GP11ObjectData *data = GP11_OBJECT_GET_DATA (obj);
+	GP11Object *self = GP11_OBJECT (obj);
+	
+	/* The sets to data below are only allowed during construction */ 
 	
 	switch (prop_id) {
 	case PROP_MODULE:
-		g_return_if_fail (!object->module);
-		object->module = g_value_get_object (value);
-		g_return_if_fail (object->module);
-		g_object_ref (object->module);
+		g_return_if_fail (!data->module);
+		data->module = g_value_get_object (value);
+		g_return_if_fail (data->module);
+		g_object_ref (data->module);
 		break;
 	case PROP_SLOT:
-		g_return_if_fail (!object->slot);
-		object->slot = g_value_get_object (value);
-		g_return_if_fail (object->slot);
-		g_object_ref (object->slot);
+		g_return_if_fail (!data->slot);
+		data->slot = g_value_get_object (value);
+		g_return_if_fail (data->slot);
+		g_object_ref (data->slot);
 		break;
 	case PROP_SESSION:
-		gp11_object_set_session (object, g_value_get_object (value));
+		gp11_object_set_session (self, g_value_get_object (value));
 		break;
 	case PROP_HANDLE:
-		g_return_if_fail (!object->handle);
-		object->handle = g_value_get_uint (value);
+		g_return_if_fail (!data->handle);
+		data->handle = g_value_get_ulong (value);
 		break;
 	}
 }
 
 static void
-gp11_object_dispose (GObject *obj)
+gp11_object_finalize (GObject *obj)
 {
-	GP11Object *object = GP11_OBJECT (obj);
+	GP11ObjectPrivate *pv = (G_TYPE_INSTANCE_GET_PRIVATE(obj, GP11_TYPE_OBJECT, GP11ObjectPrivate));
+	GP11ObjectData *data = GP11_OBJECT_GET_DATA (obj);
+
+	if (data->slot)
+		g_object_unref (data->slot);
+	data->slot = NULL;
 	
-	if (object->slot)
-		g_object_unref (object->slot);
-	object->slot = NULL;
+	if (data->module)
+		g_object_unref (data->module);
+	data->module = NULL;
 	
-	if (object->module)
-		g_object_unref (object->module);
-	object->module = NULL;
+	if (pv->session)
+		g_object_unref (pv->session);
+	pv->session = NULL;
 	
-	if (object->session)
-		g_object_unref (object->session);
-	object->session = NULL;
-
-	G_OBJECT_CLASS (gp11_object_parent_class)->dispose (obj);
-}
-
-static void
-gp11_object_finalize (GObject *obj)
-{
-	GP11Object *object = GP11_OBJECT (obj);
-
-	g_assert (object->slot == NULL);
-	g_assert (object->module == NULL);
-	g_assert (object->session == NULL);
+	data->handle = 0;
 	
-	object->handle = 0;
+	g_static_mutex_free (&pv->mutex);
 	
 	G_OBJECT_CLASS (gp11_object_parent_class)->finalize (obj);
 }
@@ -206,7 +233,6 @@
 	
 	gobject_class->get_property = gp11_object_get_property;
 	gobject_class->set_property = gp11_object_set_property;
-	gobject_class->dispose = gp11_object_dispose;
 	gobject_class->finalize = gp11_object_finalize;
 	
 	g_object_class_install_property (gobject_class, PROP_MODULE,
@@ -218,12 +244,14 @@
 		                     GP11_TYPE_SLOT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property (gobject_class, PROP_HANDLE,
-		g_param_spec_uint ("handle", "Object Handle", "PKCS11 Object Handle",
-		                   0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+		g_param_spec_ulong ("handle", "Object Handle", "PKCS11 Object Handle",
+		                   0, G_MAXULONG, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property (gobject_class, PROP_SESSION,
 		g_param_spec_object ("session", "session", "PKCS11 Session to make calls on",
 		                     GP11_TYPE_SESSION, G_PARAM_READWRITE));
+	
+	g_type_class_add_private (klass, sizeof (GP11ObjectPrivate));
 }
 
 /* ----------------------------------------------------------------------------
@@ -243,8 +271,16 @@
 GP11Object*
 gp11_object_from_handle (GP11Slot *slot, CK_OBJECT_HANDLE handle)
 {
+	GP11Module *module = NULL;
+	GP11Object *object;
+	
 	g_return_val_if_fail (GP11_IS_SLOT (slot), NULL);
-	return g_object_new (GP11_TYPE_OBJECT, "module", slot->module, "handle", handle, "slot", slot, NULL);
+	
+	module = gp11_slot_get_module (slot);
+	object = g_object_new (GP11_TYPE_OBJECT, "module", module, "handle", handle, "slot", slot, NULL);
+	g_object_unref (module);
+	
+	return object;
 }
 
 /**
@@ -277,22 +313,57 @@
 
 /**
  * gp11_object_get_handle:
- * @object: The object.
+ * @self: The object.
  * 
  * Get the raw PKCS#11 handle of a GP11Object.
  * 
  * Return value: The raw object handle.
  **/
 CK_OBJECT_HANDLE
-gp11_object_get_handle (GP11Object *object)
+gp11_object_get_handle (GP11Object *self)
+{
+	GP11ObjectData *data = GP11_OBJECT_GET_DATA (self);
+	g_return_val_if_fail (GP11_IS_OBJECT (self), (CK_OBJECT_HANDLE)-1);
+	return data->handle;
+}
+
+/**
+ * gp11_object_get_module:
+ * @self: The object.
+ * 
+ * Get the PKCS#11 module to which this object belongs.
+ * 
+ * Return value: The module, which should be unreffed after use.
+ **/
+GP11Module*
+gp11_object_get_module (GP11Object *self)
+{
+	GP11ObjectData *data = GP11_OBJECT_GET_DATA (self);
+	g_return_val_if_fail (GP11_IS_OBJECT (self), NULL);
+	g_return_val_if_fail (GP11_IS_MODULE (data->module), NULL);
+	return g_object_ref (data->module);
+}
+
+/**
+ * gp11_object_get_slot:
+ * @self: The object.
+ * 
+ * Get the PKCS#11 slot to which this object belongs.
+ * 
+ * Return value: The slot, which should be unreffed after use.
+ **/
+GP11Slot*
+gp11_object_get_slot (GP11Object *self)
 {
-	g_return_val_if_fail (GP11_IS_OBJECT (object), (CK_OBJECT_HANDLE)-1);
-	return object->handle;
+	GP11ObjectData *data = GP11_OBJECT_GET_DATA (self);
+	g_return_val_if_fail (GP11_IS_OBJECT (self), NULL);
+	g_return_val_if_fail (GP11_IS_SLOT (data->slot), NULL);
+	return g_object_ref (data->slot);
 }
 
 /**
  * gp11_object_get_session:
- * @object: The object
+ * @self: The object
  * 
  * Get the PKCS#11 session assigned to make calls on when operating
  * on this object.  
@@ -301,18 +372,30 @@
  * object. By default an object will open and close sessions 
  * appropriate for its calls.
  * 
- * Return value: The assigned session.   
+ * Return value: The assigned session, which must be unreffed after use.
  **/
 GP11Session*
-gp11_object_get_session (GP11Object *object)
+gp11_object_get_session (GP11Object *self)
 {
-	g_return_val_if_fail (GP11_IS_OBJECT (object), NULL);
-	return object->session;
+	GP11ObjectPrivate *pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GP11_TYPE_OBJECT, GP11ObjectPrivate));
+	GP11Session *session;
+	
+	g_return_val_if_fail (GP11_IS_OBJECT (self), NULL);
+	
+	g_static_mutex_lock (&pv->mutex);
+	
+	{
+		session = pv->session ? g_object_ref (pv->session) : NULL;
+	}
+	
+	g_static_mutex_unlock (&pv->mutex);
+	
+	return session;
 }
 
 /**
- * gp11_object_get_session:
- * @object: The object
+ * gp11_object_set_session:
+ * @self: The object
  * @session: The assigned session
  * 
  * Set the PKCS#11 session assigned to make calls on when operating
@@ -326,14 +409,23 @@
  * that modify the state of the object will probably fail.
  **/
 void
-gp11_object_set_session (GP11Object *object, GP11Session *session)
+gp11_object_set_session (GP11Object *self, GP11Session *session)
 {
-	g_return_if_fail (GP11_IS_OBJECT (object));
-	if (session)
-		g_object_ref (session);
-	if (object->session)
-		g_object_unref (object->session);
-	object->session = session;
+	GP11ObjectPrivate *pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GP11_TYPE_OBJECT, GP11ObjectPrivate));
+
+	g_return_if_fail (GP11_IS_OBJECT (self));
+	
+	g_static_mutex_lock (&pv->mutex);
+	
+	{
+		if (session)
+			g_object_ref (session);
+		if (pv->session)
+			g_object_unref (pv->session);
+		pv->session = session;
+	}
+	
+	g_static_mutex_unlock (&pv->mutex);
 }
 
 /* DESTROY */
@@ -351,7 +443,7 @@
 
 /**
  * gp11_object_destroy:
- * @object: The object to destroy.
+ * @self: The object to destroy.
  * @err: A location to return an error.
  * 
  * Destroy a PKCS#11 object, deleting it from storage or the session.
@@ -360,14 +452,14 @@
  * Return value: Whether the call was successful or not.
  **/
 gboolean
-gp11_object_destroy (GP11Object *object, GError **err)
+gp11_object_destroy (GP11Object *self, GError **err)
 {
-	return gp11_object_destroy_full (object, NULL, err);
+	return gp11_object_destroy_full (self, NULL, err);
 }
 
 /**
  * gp11_object_destroy_full:
- * @object: The object to destroy.
+ * @self: The object to destroy.
  * @cancellable: Optional cancellable object, or NULL to ignore. 
  * @err: A location to return an error.
  * 
@@ -377,18 +469,19 @@
  * Return value: Whether the call was successful or not.
  **/
 gboolean
-gp11_object_destroy_full (GP11Object *object, GCancellable *cancellable, GError **err)
+gp11_object_destroy_full (GP11Object *self, GCancellable *cancellable, GError **err)
 {
+	GP11ObjectData *data = GP11_OBJECT_GET_DATA (self);
 	Destroy args = { GP11_ARGUMENTS_INIT, 0 };
 	GP11Session *session;
 	gboolean ret = FALSE;
 	
-	g_return_val_if_fail (GP11_IS_OBJECT (object), FALSE);
-	g_return_val_if_fail (GP11_IS_SLOT (object->slot), FALSE);
+	g_return_val_if_fail (GP11_IS_OBJECT (self), FALSE);
+	g_return_val_if_fail (GP11_IS_SLOT (data->slot), FALSE);
 	
-	args.object = object->handle;
+	args.object = data->handle;
 
-	session = require_session_sync (object, CKF_RW_SESSION, err);
+	session = require_session_sync (self, CKF_RW_SESSION, err);
 	if (session)
 		ret = _gp11_call_sync (session, perform_destroy, &args, cancellable, err);
 	g_object_unref (session);
@@ -397,7 +490,7 @@
 
 /**
  * gp11_object_destroy_async:
- * @object: The object to destroy.
+ * @self: The object to destroy.
  * @cancellable: Optional cancellable object, or NULL to ignore. 
  * @callback: Callback which is called when operation completes.
  * @user_data: Data to pass to the callback.
@@ -406,25 +499,26 @@
  * This call will return immediately and complete asynchronously.
  **/
 void
-gp11_object_destroy_async (GP11Object *object, GCancellable *cancellable,
+gp11_object_destroy_async (GP11Object *self, GCancellable *cancellable,
                            GAsyncReadyCallback callback, gpointer user_data)
 {
+	GP11ObjectData *data = GP11_OBJECT_GET_DATA (self);
 	Destroy* args;
 	GP11Call *call;
 
-	g_return_if_fail (GP11_IS_OBJECT (object));
-	g_return_if_fail (GP11_IS_SLOT (object->slot));
+	g_return_if_fail (GP11_IS_OBJECT (self));
+	g_return_if_fail (GP11_IS_SLOT (data->slot));
 
-	args = _gp11_call_async_prep (NULL, object, perform_destroy, sizeof (*args), NULL);
-	args->object = object->handle;
+	args = _gp11_call_async_prep (data->slot, self, perform_destroy, sizeof (*args), NULL);
+	args->object = data->handle;
 	
 	call = _gp11_call_async_ready (args, cancellable, callback, user_data);
-	require_session_async (object, call, CKF_RW_SESSION, cancellable);
+	require_session_async (self, call, CKF_RW_SESSION, cancellable);
 }
 
 /**
  * gp11_object_destroy_finish:
- * @object: The object being destroyed.
+ * @self: The object being destroyed.
  * @result: The result of the destory operation passed to the callback.
  * @err: A location to store an error.
  * 
@@ -434,7 +528,7 @@
  * Return value: Whether the object was destroyed successfully or not.
  */
 gboolean
-gp11_object_destroy_finish (GP11Object *object, GAsyncResult *result, GError **err)
+gp11_object_destroy_finish (GP11Object *self, GAsyncResult *result, GError **err)
 {
 	return _gp11_call_basic_finish (result, err);
 }
@@ -462,7 +556,7 @@
 
 /**
  * gp11_object_set:
- * @object: The object to set attributes on.
+ * @self: The object to set attributes on.
  * @err: A location to return an error.
  * ...: The attributes to set.
  *
@@ -493,7 +587,7 @@
  * Return value: Whether the call was successful or not.
  **/
 gboolean
-gp11_object_set (GP11Object *object, GError **err, ...)
+gp11_object_set (GP11Object *self, GError **err, ...)
 {
 	GP11Attributes *attrs;
 	va_list va;
@@ -503,7 +597,7 @@
 	attrs = gp11_attributes_new_valist (va);
 	va_end (va);
 	
-	rv = gp11_object_set_full (object, attrs, NULL, err);
+	rv = gp11_object_set_full (self, attrs, NULL, err);
 	
 	gp11_attributes_unref (attrs);
 	return rv;
@@ -511,7 +605,7 @@
 
 /**
  * gp11_object_set_full:
- * @object: The object to set attributes on.
+ * @self: The object to set attributes on.
  * @attrs: The attributes to set on the object.
  * @cancellable: Optional cancellable object, or NULL to ignore. 
  * @err: A location to return an error.
@@ -521,20 +615,21 @@
  * Return value: Whether the call was successful or not.
  **/
 gboolean
-gp11_object_set_full (GP11Object *object, GP11Attributes *attrs,
+gp11_object_set_full (GP11Object *self, GP11Attributes *attrs,
                       GCancellable *cancellable, GError **err)
 {
+	GP11ObjectData *data = GP11_OBJECT_GET_DATA (self);
 	SetAttributes args;
 	GP11Session *session;
 	gboolean ret = FALSE;
 	
-	g_return_val_if_fail (GP11_IS_OBJECT (object), FALSE);
+	g_return_val_if_fail (GP11_IS_OBJECT (self), FALSE);
 	
 	memset (&args, 0, sizeof (args));
 	args.attrs = attrs;
-	args.object = object->handle;
+	args.object = data->handle;
 
-	session = require_session_sync (object, CKF_RW_SESSION, err);
+	session = require_session_sync (self, CKF_RW_SESSION, err);
 	if (session)
 		ret = _gp11_call_sync (session, perform_set_attributes, &args, cancellable, err);
 	g_object_unref (session);
@@ -543,7 +638,7 @@
 
 /**
  * gp11_object_set_async:
- * @object: The object to set attributes on.
+ * @self: The object to set attributes on.
  * @attrs: The attributes to set on the object.
  * @cancellable: Optional cancellable object, or NULL to ignore. 
  * @callback: Callback which is called when operation completes.
@@ -553,27 +648,28 @@
  * immediately and completes asynchronously.
  **/
 void
-gp11_object_set_async (GP11Object *object, GP11Attributes *attrs, GCancellable *cancellable,
+gp11_object_set_async (GP11Object *self, GP11Attributes *attrs, GCancellable *cancellable,
                        GAsyncReadyCallback callback, gpointer user_data)
 {
+	GP11ObjectData *data = GP11_OBJECT_GET_DATA (self);
 	SetAttributes *args;
 	GP11Call *call;
 	
-	g_return_if_fail (GP11_IS_OBJECT (object));
+	g_return_if_fail (GP11_IS_OBJECT (self));
 
-	args = _gp11_call_async_prep (object->slot, object, perform_set_attributes, 
+	args = _gp11_call_async_prep (data->slot, self, perform_set_attributes, 
 	                              sizeof (*args), free_set_attributes);
 	args->attrs = attrs;
 	gp11_attributes_ref (attrs);
-	args->object = object->handle;
+	args->object = data->handle;
 	
 	call = _gp11_call_async_ready (args, cancellable, callback, user_data);
-	require_session_async (object, call, CKF_RW_SESSION, cancellable);
+	require_session_async (self, call, CKF_RW_SESSION, cancellable);
 }
 
 /**
  * gp11_object_set_finish:
- * @object: The object to set attributes on.
+ * @self: The object to set attributes on.
  * @result: The result of the destory operation passed to the callback.
  * @err: A location to store an error.
  * 
@@ -583,7 +679,7 @@
  * Return value: Whether the attributes were successfully set on the object or not.
  */
 gboolean
-gp11_object_set_finish (GP11Object *object, GAsyncResult *result, GError **err)
+gp11_object_set_finish (GP11Object *self, GAsyncResult *result, GError **err)
 {
 	return _gp11_call_basic_finish (result, err);
 }
@@ -682,7 +778,7 @@
 
 /**
  * gp11_object_get:
- * @object: The object to get attributes from.
+ * @self: The object to get attributes from.
  * @err: A location to store an error.
  * ...: The attribute types to get.
  * 
@@ -695,7 +791,7 @@
  * Return value: The resulting PKCS#11 attributes, or NULL if an error occurred. 
  **/
 GP11Attributes*
-gp11_object_get (GP11Object *object, GError **err, ...)
+gp11_object_get (GP11Object *self, GError **err, ...)
 {
 	GP11Attributes *result;
 	GArray *array;
@@ -712,14 +808,14 @@
 	}
 	va_end (va);
 	
-	result = gp11_object_get_full (object, (gulong*)array->data, array->len, NULL, err);
+	result = gp11_object_get_full (self, (gulong*)array->data, array->len, NULL, err);
 	g_array_free (array, TRUE);
 	return result;
 }
 
 /**
  * gp11_object_get:
- * @object: The object to get attributes from.
+ * @self: The object to get attributes from.
  * @attr_types: The attributes to get.
  * @n_attr_types: The number of attributes to get.
  * @cancellable: Optional cancellation object, or NULL.
@@ -734,22 +830,23 @@
  * Return value: The resulting PKCS#11 attributes, or NULL if an error occurred. 
  **/
 GP11Attributes*
-gp11_object_get_full (GP11Object *object, const gulong *attr_types, gsize n_attr_types,
+gp11_object_get_full (GP11Object *self, const gulong *attr_types, gsize n_attr_types,
                       GCancellable *cancellable, GError **err)
 {
+	GP11ObjectData *data = GP11_OBJECT_GET_DATA (self);
 	GetAttributes args;
 	GP11Session *session;
 	
-	g_return_val_if_fail (GP11_IS_OBJECT (object), FALSE);
+	g_return_val_if_fail (GP11_IS_OBJECT (self), FALSE);
 	
-	session = require_session_sync (object, 0, err);
+	session = require_session_sync (self, 0, err);
 	if (!session)
 		return NULL;
 	
 	memset (&args, 0, sizeof (args));
 	args.attr_types = (gulong*)attr_types;
 	args.n_attr_types = n_attr_types;
-	args.object = object->handle;
+	args.object = data->handle;
 
 	if (!_gp11_call_sync (session, perform_get_attributes, &args, cancellable, err)) {
 		gp11_attributes_unref (args.results);
@@ -763,7 +860,7 @@
 
 /**
  * gp11_object_get_async:
- * @object: The object to get attributes from.
+ * @self: The object to get attributes from.
  * @attr_types: The attributes to get.
  * @n_attr_types: The number of attributes to get.
  * @cancellable: Optional cancellation object, or NULL.
@@ -774,28 +871,29 @@
  * immediately and completes asynchronously.
  **/
 void
-gp11_object_get_async (GP11Object *object, const gulong *attr_types, gsize n_attr_types,
+gp11_object_get_async (GP11Object *self, const gulong *attr_types, gsize n_attr_types,
                        GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
 {
+	GP11ObjectData *data = GP11_OBJECT_GET_DATA (self);
 	GetAttributes *args;
 	GP11Call *call;
 	
-	g_return_if_fail (GP11_IS_OBJECT (object));
+	g_return_if_fail (GP11_IS_OBJECT (self));
 
-	args = _gp11_call_async_prep (object->session, object, perform_get_attributes, 
+	args = _gp11_call_async_prep (data->slot, self, perform_get_attributes, 
 	                              sizeof (*args), free_get_attributes);
 	args->n_attr_types = n_attr_types;
 	if (n_attr_types)
 		args->attr_types = g_memdup (attr_types, sizeof (gulong) * n_attr_types);
-	args->object = object->handle;
+	args->object = data->handle;
 	
 	call = _gp11_call_async_ready (args, cancellable, callback, user_data);
-	require_session_async (object, call, 0, cancellable);
+	require_session_async (self, call, 0, cancellable);
 }
 
 /**
  * gp11_object_get_finish:
- * @object: The object to get attributes from.
+ * @self: The object to get attributes from.
  * @result: The result passed to the callback.
  * @err: A location to store an error.
  * 
@@ -808,7 +906,7 @@
  * Return value: The resulting PKCS#11 attributes, or NULL if an error occurred. 
  **/
 GP11Attributes*
-gp11_object_get_finish (GP11Object *object, GAsyncResult *result, GError **err)
+gp11_object_get_finish (GP11Object *self, GAsyncResult *result, GError **err)
 {
 	GP11Attributes *results;
 	GetAttributes *args;
@@ -826,7 +924,7 @@
 
 /**
  * gp11_object_get_one:
- * @object: The object to get an attribute from.
+ * @self: The object to get an attribute from.
  * @attr_type: The attribute to get.
  * @err: A location to store an error.
  * 
@@ -836,14 +934,14 @@
  * Return value: The resulting PKCS#11 attribute, or NULL if an error occurred. 
  **/
 GP11Attribute*
-gp11_object_get_one (GP11Object *object, gulong attr_type, GError **err)
+gp11_object_get_one (GP11Object *self, gulong attr_type, GError **err)
 {
-	return gp11_object_get_one_full (object, attr_type, NULL, err);
+	return gp11_object_get_one_full (self, attr_type, NULL, err);
 }
 
 /**
  * gp11_object_get_one_full:
- * @object: The object to get an attribute from.
+ * @self: The object to get an attribute from.
  * @attr_type: The attribute to get.
  * @cancellable: Optional cancellation object, or NULL.
  * @err: A location to store an error.
@@ -854,13 +952,13 @@
  * Return value: The resulting PKCS#11 attribute, or NULL if an error occurred. 
  **/
 GP11Attribute*
-gp11_object_get_one_full (GP11Object *object, gulong attr_type, 
+gp11_object_get_one_full (GP11Object *self, gulong attr_type, 
                           GCancellable *cancellable, GError **err)
 {
 	GP11Attributes *attrs;
 	GP11Attribute *attr;
 	
-	attrs = gp11_object_get_full (object, &attr_type, 1, cancellable, err);
+	attrs = gp11_object_get_full (self, &attr_type, 1, cancellable, err);
 	if (!attrs || !gp11_attributes_count (attrs))
 		return NULL;
 	
@@ -873,7 +971,7 @@
 
 /**
  * gp11_object_get_one_async:
- * @object: The object to get an attribute from.
+ * @self: The object to get an attribute from.
  * @attr_type: The attribute to get.
  * @cancellable: Optional cancellation object, or NULL.
  * @callback: Called when the operation completes.
@@ -883,15 +981,15 @@
  * return immediately and complete asynchronously.
  **/
 void
-gp11_object_get_one_async (GP11Object *object, gulong attr_type, GCancellable *cancellable,
+gp11_object_get_one_async (GP11Object *self, gulong attr_type, GCancellable *cancellable,
                            GAsyncReadyCallback callback, gpointer user_data)
 {
-	gp11_object_get_async (object, &attr_type, 1, cancellable, callback, user_data);
+	gp11_object_get_async (self, &attr_type, 1, cancellable, callback, user_data);
 }
 
 /**
  * gp11_object_get_one_finish:
- * @object: The object to get an attribute from.
+ * @self: The object to get an attribute from.
  * @result: The result passed to the callback.
  * @err: A location to store an error.
  *
@@ -902,12 +1000,12 @@
  **/
 
 GP11Attribute*
-gp11_object_get_one_finish (GP11Object *object, GAsyncResult *result, GError **err)
+gp11_object_get_one_finish (GP11Object *self, GAsyncResult *result, GError **err)
 {
 	GP11Attributes *attrs;
 	GP11Attribute *attr;
 	
-	attrs = gp11_object_get_finish (object, result, err);
+	attrs = gp11_object_get_finish (self, result, err);
 	if (!attrs)
 		return NULL;
 	

Modified: trunk/gp11/gp11-session.c
==============================================================================
--- trunk/gp11/gp11-session.c	(original)
+++ trunk/gp11/gp11-session.c	Sat Dec 27 18:29:23 2008
@@ -24,6 +24,7 @@
 #include "config.h"
 
 #include "gp11.h"
+#include "gp11-marshal.h"
 #include "gp11-private.h"
 
 #include <string.h>
@@ -40,6 +41,21 @@
 	PROP_SLOT
 };
 
+typedef struct _GP11SessionData {
+	GP11Slot *slot;
+	GP11Module *module;
+	CK_SESSION_HANDLE handle;
+	gint discarded;
+} GP11SessionData;
+
+typedef struct _GP11SessionPrivate {
+	GP11SessionData data;
+	/* Add mutex and future MT-unsafe members here */
+} GP11SessionPrivate;
+
+#define GP11_SESSION_GET_DATA(o) \
+      (G_TYPE_INSTANCE_GET_PRIVATE((o), GP11_TYPE_SESSION, GP11SessionData))
+
 G_DEFINE_TYPE (GP11Session, gp11_session, G_TYPE_OBJECT);
 
 static guint signals[LAST_SIGNAL] = { 0 };
@@ -48,51 +64,78 @@
  * OBJECT
  */
 
-static void
-gp11_session_init (GP11Session *session)
+static gboolean
+gp11_session_real_discard_handle (GP11Session *self, CK_OBJECT_HANDLE handle)
 {
+	GP11SessionData *data = GP11_SESSION_GET_DATA (self);
+	CK_FUNCTION_LIST_PTR funcs;
+	CK_RV rv;
+
+	/* The default functionality, close the handle */
+
+	g_return_val_if_fail (data->module, FALSE);
+	g_object_ref (data->module);
+	
+	funcs = gp11_module_get_function_list (data->module);
+	g_return_val_if_fail (funcs, FALSE);
 	
+	rv = (funcs->C_CloseSession) (handle);
+	if (rv != CKR_OK) {
+		g_warning ("couldn't close session properly: %s",
+		           gp11_message_from_rv (rv));
+	}
+	
+	g_object_unref (data->module);
+	return TRUE;
+}
+
+static void
+gp11_session_init (GP11Session *self)
+{
+
 }
 
 static void
 gp11_session_get_property (GObject *obj, guint prop_id, GValue *value, 
                            GParamSpec *pspec)
 {
-	GP11Session *session = GP11_SESSION (obj);
+	GP11Session *self = GP11_SESSION (obj);
 
 	switch (prop_id) {
 	case PROP_MODULE:
-		g_value_set_object (value, session->module);
+		g_value_take_object (value, gp11_session_get_module (self));
 		break;
 	case PROP_HANDLE:
-		g_value_set_uint (value, session->handle);
+		g_value_set_ulong (value, gp11_session_get_handle (self));
 		break;
 	case PROP_SLOT:
-		g_value_set_object(value, session->slot);
+		g_value_take_object (value, gp11_session_get_slot (self));
 		break;
 	}
 }
 
 static void
 gp11_session_set_property (GObject *obj, guint prop_id, const GValue *value, 
-                        GParamSpec *pspec)
+                           GParamSpec *pspec)
 {
-	GP11Session *session = GP11_SESSION (obj);
+	GP11SessionData *data = GP11_SESSION_GET_DATA (obj);
+	
+	/* Only valid calls are from constructor */
 
 	switch (prop_id) {
 	case PROP_MODULE:
-		g_return_if_fail (!session->module);
-		session->module = g_value_dup_object (value);
-		g_return_if_fail (session->module);
+		g_return_if_fail (!data->module);
+		data->module = g_value_dup_object (value);
+		g_return_if_fail (data->module);
 		break;
 	case PROP_HANDLE:
-		g_return_if_fail (!session->handle);
-		session->handle = g_value_get_uint (value);
+		g_return_if_fail (!data->handle);
+		data->handle = g_value_get_ulong (value);
 		break;
 	case PROP_SLOT:
-		g_return_if_fail (!session->slot);
-		session->slot = g_value_dup_object (value);
-		g_return_if_fail (session->slot);
+		g_return_if_fail (!data->slot);
+		data->slot = g_value_dup_object (value);
+		g_return_if_fail (data->slot);
 		break;
 	}
 }
@@ -100,51 +143,47 @@
 static void
 gp11_session_dispose (GObject *obj)
 {
-	GP11Session *session = GP11_SESSION (obj);
-	CK_RV rv;
+	GP11SessionData *data = GP11_SESSION_GET_DATA (obj);
+	GP11Session *self = GP11_SESSION (obj);
+	gboolean handled;
+	gint discarded;
 
-	g_return_if_fail (GP11_IS_SESSION (session));
-	
-	/* 
-	 * Let the world know that we're discarding the session 
-	 * handle. This allows session reuse to work.
-	 */
-	if (session->handle)
-		g_signal_emit_by_name (session, "discard-handle");
-	
-	if (session->handle) {
-		g_return_if_fail (session->module && session->module->funcs);
-		rv = (session->module->funcs->C_CloseSession) (session->handle);
-		if (rv != CKR_OK) {
-			g_warning ("couldn't close session properly: %s",
-			           gp11_message_from_rv (rv));
-		}
-		session->handle = 0;
-	}
+	g_return_if_fail (GP11_IS_SESSION (self));
 	
-	if (session->slot)
-		g_object_unref (session->slot);
-	session->slot = NULL;
-
-	if (session->module)
-		g_object_unref (session->module);
-	session->module = NULL;
+	discarded = g_atomic_int_get (&data->discarded);
+	if (!discarded && g_atomic_int_compare_and_exchange (&data->discarded, discarded, 1)) {
 	
+		/* 
+		 * Let the world know that we're discarding the session 
+		 * handle. This allows session reuse to work.
+		 */
+		
+		g_signal_emit_by_name (self, "discard-handle", data->handle, &handled);
+		g_return_if_fail (handled);
+
+	}
+
 	G_OBJECT_CLASS (gp11_session_parent_class)->dispose (obj);
 }
 
 static void
 gp11_session_finalize (GObject *obj)
 {
-	GP11Session *session = GP11_SESSION (obj);
+	GP11SessionData *data = GP11_SESSION_GET_DATA (obj);
 
-	g_assert (session->module == NULL);
-	g_assert (session->handle == 0);
+	g_assert (data->discarded != 0);
+	
+	if (data->slot)
+		g_object_unref (data->slot);
+	data->slot = NULL;
+
+	if (data->module)
+		g_object_unref (data->module);
+	data->module = NULL;
 	
 	G_OBJECT_CLASS (gp11_session_parent_class)->finalize (obj);
 }
 
-
 static void
 gp11_session_class_init (GP11SessionClass *klass)
 {
@@ -156,22 +195,26 @@
 	gobject_class->dispose = gp11_session_dispose;
 	gobject_class->finalize = gp11_session_finalize;
 	
+	klass->discard_handle = gp11_session_real_discard_handle;
+	
 	g_object_class_install_property (gobject_class, PROP_MODULE,
 		g_param_spec_object ("module", "Module", "PKCS11 Module",
 		                     GP11_TYPE_MODULE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property (gobject_class, PROP_HANDLE,
-		g_param_spec_uint ("handle", "Session Handle", "PKCS11 Session Handle",
-		                   0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+		g_param_spec_ulong ("handle", "Session Handle", "PKCS11 Session Handle",
+		                    0, G_MAXULONG, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property (gobject_class, PROP_SLOT,
 		g_param_spec_object ("slot", "Slot that this session uses", "PKCS11 Slot",
 		                     GP11_TYPE_SLOT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 	
 	signals[DISCARD_HANDLE] = g_signal_new ("discard-handle", GP11_TYPE_SESSION, 
-			G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GP11SessionClass, discard_handle),
-			NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
-
+	                G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GP11SessionClass, discard_handle),
+			g_signal_accumulator_true_handled, NULL, 
+			_gp11_marshal_BOOLEAN__ULONG, G_TYPE_BOOLEAN, 1, G_TYPE_ULONG);
+	
+	g_type_class_add_private (klass, sizeof (GP11SessionPrivate));
 }
 
 /* ----------------------------------------------------------------------------
@@ -206,29 +249,72 @@
 GP11Session*
 gp11_session_from_handle (GP11Slot *slot, CK_SESSION_HANDLE handle)
 {
+	GP11Module *module;
+	GP11Session *session;
+	
 	g_return_val_if_fail (GP11_IS_SLOT (slot), NULL);
-	return g_object_new (GP11_TYPE_SESSION, "module", slot->module, 
-	                     "handle", handle, "slot", slot, NULL);
+	
+	module = gp11_slot_get_module (slot);
+	session = g_object_new (GP11_TYPE_SESSION, "module", module, 
+	                        "handle", handle, "slot", slot, NULL);
+	g_object_unref (module);
+	
+	return session;
 }
 
 /**
  * gp11_session_get_handle:
- * @session: The session object.
+ * @self: The session object.
  * 
  * Get the raw PKCS#11 session handle from a GP11Session object.
  * 
  * Return value: The raw session handle.
  **/
 CK_SESSION_HANDLE
-gp11_session_get_handle (GP11Session *session)
+gp11_session_get_handle (GP11Session *self)
 {
-	g_return_val_if_fail (GP11_IS_SESSION (session), (CK_SESSION_HANDLE)-1);
-	return session->handle;
+	GP11SessionData *data = GP11_SESSION_GET_DATA (self);
+	g_return_val_if_fail (GP11_IS_SESSION (self), (CK_SESSION_HANDLE)-1);
+	return data->handle;
+}
+
+/**
+ * gp11_session_get_module:
+ * @self: The session object.
+ * 
+ * Get the PKCS#11 module to which this session belongs.
+ * 
+ * Return value: The module, which should be unreffed after use.
+ **/
+GP11Module*
+gp11_session_get_module (GP11Session *self)
+{
+	GP11SessionData *data = GP11_SESSION_GET_DATA (self);
+	g_return_val_if_fail (GP11_IS_SESSION (self), NULL);
+	g_return_val_if_fail (GP11_IS_MODULE (data->module), NULL);
+	return g_object_ref (data->module);
+}
+
+/**
+ * gp11_session_get_slot:
+ * @self: The session object.
+ * 
+ * Get the PKCS#11 slot to which this session belongs.
+ * 
+ * Return value: The slot, which should be unreffed after use.
+ **/
+GP11Slot*
+gp11_session_get_slot (GP11Session *self)
+{
+	GP11SessionData *data = GP11_SESSION_GET_DATA (self);
+	g_return_val_if_fail (GP11_IS_SESSION (self), NULL);
+	g_return_val_if_fail (GP11_IS_SLOT (data->slot), NULL);
+	return g_object_ref (data->slot);
 }
 
 /**
  * gp11_session_get_info: 
- * @session: The session object.
+ * @self: The session object.
  * 
  * Get information about the session.
  * 
@@ -236,18 +322,27 @@
  * when done.
  **/
 GP11SessionInfo*
-gp11_session_get_info (GP11Session *session)
+gp11_session_get_info (GP11Session *self)
 {
+	GP11SessionData *data = GP11_SESSION_GET_DATA (self);
 	GP11SessionInfo *sessioninfo;
+	CK_FUNCTION_LIST_PTR funcs;
 	CK_SESSION_INFO info;
 	CK_RV rv;
 	
-	g_return_val_if_fail (GP11_IS_SESSION (session), NULL);
-	g_return_val_if_fail (GP11_IS_MODULE (session->module), NULL);
-	g_return_val_if_fail (session->module->funcs, NULL);
+	g_return_val_if_fail (GP11_IS_SESSION (self), NULL);
+	g_return_val_if_fail (GP11_IS_MODULE (data->module), NULL);
+	
+	g_object_ref (data->module);
+	
+	funcs = gp11_module_get_function_list (data->module);
+	g_return_val_if_fail (funcs, NULL);
 	
 	memset (&info, 0, sizeof (info));
-	rv = (session->module->funcs->C_GetSessionInfo) (session->handle, &info);
+	rv = (funcs->C_GetSessionInfo) (data->handle, &info);
+	
+	g_object_unref (data->module);
+	
 	if (rv != CKR_OK) {
 		g_warning ("couldn't get session info: %s", gp11_message_from_rv (rv));
 		return NULL;
@@ -289,7 +384,7 @@
 
 /**
  * gp11_session_login:
- * @session: Log into this session.
+ * @self: Log into this session.
  * @user_type: The type of login user.
  * @pin: The user's PIN, or NULL for protected authentication path.
  * @n_pin: The length of the PIN.
@@ -301,15 +396,15 @@
  * Return value: Whether successful or not.
  **/
 gboolean
-gp11_session_login (GP11Session *session, gulong user_type, const guchar *pin,
+gp11_session_login (GP11Session *self, gulong user_type, const guchar *pin,
                     gsize n_pin, GError **err)
 {
-	return gp11_session_login_full (session, user_type, pin, n_pin, NULL, err);
+	return gp11_session_login_full (self, user_type, pin, n_pin, NULL, err);
 }
 
 /**
  * gp11_session_login_full:
- * @session: Log into this session.
+ * @self: Log into this session.
  * @user_type: The type of login user.
  * @pin: The user's PIN, or NULL for protected authentication path.
  * @n_pin: The length of the PIN.
@@ -322,17 +417,17 @@
  * Return value: Whether successful or not.
  **/
 gboolean
-gp11_session_login_full (GP11Session *session, gulong user_type, const guchar *pin,
+gp11_session_login_full (GP11Session *self, gulong user_type, const guchar *pin,
                          gsize n_pin, GCancellable *cancellable, GError **err)
 {
 	Login args = { GP11_ARGUMENTS_INIT, user_type, (guchar*)pin, n_pin };
-	return _gp11_call_sync (session, perform_login, &args, cancellable, err);
+	return _gp11_call_sync (self, perform_login, &args, cancellable, err);
 	
 }
 
 /**
  * gp11_session_login_async:
- * @session: Log into this session.
+ * @self: Log into this session.
  * @user_type: The type of login user.
  * @pin: The user's PIN, or NULL for protected authentication path.
  * @n_pin: The length of the PIN.
@@ -344,11 +439,11 @@
  * immediately and completes asynchronously.
  **/
 void
-gp11_session_login_async (GP11Session *session, gulong user_type, const guchar *pin,
+gp11_session_login_async (GP11Session *self, gulong user_type, const guchar *pin,
                           gsize n_pin, GCancellable *cancellable, GAsyncReadyCallback callback,
                           gpointer user_data)
 {
-	Login* args = _gp11_call_async_prep (session, session, perform_login, sizeof (*args), free_login);
+	Login* args = _gp11_call_async_prep (self, self, perform_login, sizeof (*args), free_login);
 	
 	args->user_type = user_type;
 	args->pin = pin && n_pin ? g_memdup (pin, n_pin) : NULL;
@@ -360,7 +455,7 @@
 
 /**
  * gp11_session_login_finish:
- * @session: The session logged into.
+ * @self: The session logged into.
  * @result: The result passed to the callback.
  * @err: A location to return an error.
  * 
@@ -369,7 +464,7 @@
  * Return value: Whether the operation was successful or not.
  **/
 gboolean
-gp11_session_login_finish (GP11Session *session, GAsyncResult *result, GError **err)
+gp11_session_login_finish (GP11Session *self, GAsyncResult *result, GError **err)
 {
 	return _gp11_call_basic_finish (result, err);
 }
@@ -387,7 +482,7 @@
 
 /**
  * gp11_session_logout:
- * @session: Logout of this session.
+ * @self: Logout of this session.
  * @err: A location to return an error.
  * 
  * Log out of the session. This call may block for an indefinite period.
@@ -395,14 +490,14 @@
  * Return value: Whether the logout was successful or not.
  **/
 gboolean
-gp11_session_logout (GP11Session *session, GError **err)
+gp11_session_logout (GP11Session *self, GError **err)
 {
-	return gp11_session_logout_full (session, NULL, err);
+	return gp11_session_logout_full (self, NULL, err);
 }
 
 /**
  * gp11_session_logout_full:
- * @session: Logout of this session.
+ * @self: Logout of this session.
  * @cancellable: Optional cancellation object, or NULL.
  * @err: A location to return an error.
  * 
@@ -411,15 +506,15 @@
  * Return value: Whether the logout was successful or not.
  **/
 gboolean
-gp11_session_logout_full (GP11Session *session, GCancellable *cancellable, GError **err)
+gp11_session_logout_full (GP11Session *self, GCancellable *cancellable, GError **err)
 {
 	GP11Arguments args = GP11_ARGUMENTS_INIT;
-	return _gp11_call_sync (session, perform_logout, &args, cancellable, err);	
+	return _gp11_call_sync (self, perform_logout, &args, cancellable, err);	
 }
 
 /**
  * gp11_session_logout_async:
- * @session: Logout of this session.
+ * @self: Logout of this session.
  * @cancellable: Optional cancellation object, or NULL.
  * @callback: Called when the operation completes.
  * @user_data: Data to pass to the callback.
@@ -428,16 +523,16 @@
  * asynchronously.
  **/
 void
-gp11_session_logout_async (GP11Session *session, GCancellable *cancellable,
+gp11_session_logout_async (GP11Session *self, GCancellable *cancellable,
                            GAsyncReadyCallback callback, gpointer user_data)
 {
-	GP11Arguments *args = _gp11_call_async_prep (session, session, perform_logout, 0, NULL);
+	GP11Arguments *args = _gp11_call_async_prep (self, self, perform_logout, 0, NULL);
 	_gp11_call_async_ready_go (args, cancellable, callback, user_data);
 }
 
 /**
  * gp11_session_logout_finish:
- * @session: Logout of this session.
+ * @self: Logout of this session.
  * @result: The result passed to the callback.
  * @err: A location to return an error.
  * 
@@ -446,7 +541,7 @@
  * Return value: Whether the logout was successful or not.
  **/
 gboolean
-gp11_session_logout_finish (GP11Session *session, GAsyncResult *result, GError **err)
+gp11_session_logout_finish (GP11Session *self, GAsyncResult *result, GError **err)
 {
 	return _gp11_call_basic_finish (result, err);
 }
@@ -480,7 +575,7 @@
 
 /**
  * gp11_session_create_object:
- * @session: The session to create the object on.
+ * @self: The session to create the object on.
  * @err: A location to store an error.
  * ...: The attributes to create the new object with.
  * 
@@ -512,7 +607,7 @@
  * Return value: The newly created object, or NULL if an error occurred.
  **/
 GP11Object*
-gp11_session_create_object (GP11Session *session, GError **err, ...)
+gp11_session_create_object (GP11Session *self, GError **err, ...)
 {
 	GP11Attributes *attrs;
 	GP11Object *object;
@@ -522,14 +617,14 @@
 	attrs = gp11_attributes_new_valist (va);
 	va_end (va);
 	
-	object = gp11_session_create_object_full (session, attrs, NULL, err);
+	object = gp11_session_create_object_full (self, attrs, NULL, err);
 	gp11_attributes_unref (attrs);
 	return object;
 }
 
 /**
  * gp11_session_create_object_full:
- * @session: The session to create the object on.
+ * @self: The session to create the object on.
  * @attrs: The attributes to create the object with.
  * @cancellable: Optional cancellation object, or NULL.
  * @err: A location to return an error, or NULL.
@@ -540,18 +635,19 @@
  * Return value: The newly created object or NULL if an error occurred.
  **/
 GP11Object*
-gp11_session_create_object_full (GP11Session *session, GP11Attributes *attrs,
+gp11_session_create_object_full (GP11Session *self, GP11Attributes *attrs,
                                  GCancellable *cancellable, GError **err)
 {
+	GP11SessionData *data = GP11_SESSION_GET_DATA (self);
 	CreateObject args = { GP11_ARGUMENTS_INIT, attrs, 0 };
-	if (!_gp11_call_sync (session, perform_create_object, &args, cancellable, err))
+	if (!_gp11_call_sync (self, perform_create_object, &args, cancellable, err))
 		return NULL;
-	return gp11_object_from_handle (session->slot, args.object);
+	return gp11_object_from_handle (data->slot, args.object);
 }
 
 /**
  * gp11_session_create_object_async:
- * @session: The session to create the object on.
+ * @self: The session to create the object on.
  * @attrs: The attributes to create the object with.
  * @cancellable: Optional cancellation object or NULL.
  * @callback: Called when the operation completes.
@@ -561,11 +657,11 @@
  * and complete asynchronously.
  **/
 void
-gp11_session_create_object_async (GP11Session *session, GP11Attributes *attrs,
+gp11_session_create_object_async (GP11Session *self, GP11Attributes *attrs,
                                   GCancellable *cancellable, GAsyncReadyCallback callback, 
                                   gpointer user_data)
 {
-	CreateObject *args = _gp11_call_async_prep (session, session, perform_create_object, 
+	CreateObject *args = _gp11_call_async_prep (self, self, perform_create_object, 
 	                                            sizeof (*args), free_create_object);
 	args->attrs = attrs;
 	gp11_attributes_ref (attrs);
@@ -574,7 +670,7 @@
 
 /**
  * gp11_session_create_object_finish:
- * @session: The session to create the object on.
+ * @self: The session to create the object on.
  * @result: The result passed to the callback.
  * @err: A location to return an error, or NULL.
  * 
@@ -583,14 +679,15 @@
  * Return value: The newly created object or NULL if an error occurred.
  **/
 GP11Object*
-gp11_session_create_object_finish (GP11Session *session, GAsyncResult *result, GError **err)
+gp11_session_create_object_finish (GP11Session *self, GAsyncResult *result, GError **err)
 {
+	GP11SessionData *data = GP11_SESSION_GET_DATA (self);
 	CreateObject *args;
 	
 	if (!_gp11_call_basic_finish (result, err))
 		return NULL;
 	args = _gp11_call_arguments (result, CreateObject);
-	return gp11_object_from_handle (session->slot, args->object);
+	return gp11_object_from_handle (data->slot, args->object);
 }
 
 
@@ -666,14 +763,15 @@
 }
 
 static GList*
-objlist_from_handles (GP11Session *session, CK_OBJECT_HANDLE_PTR objects, 
+objlist_from_handles (GP11Session *self, CK_OBJECT_HANDLE_PTR objects, 
                       CK_ULONG n_objects)
 {
+	GP11SessionData *data = GP11_SESSION_GET_DATA (self);
 	GList *results = NULL;
 	
 	while (n_objects > 0) {
 		results = g_list_prepend (results, 
-		                gp11_object_from_handle (session->slot, objects[--n_objects]));
+		                gp11_object_from_handle (data->slot, objects[--n_objects]));
 	}
 	
 	return g_list_reverse (results);
@@ -681,7 +779,7 @@
 
 /**
  * gp11_session_find_objects:
- * @session: The session to find objects on.
+ * @self: The session to find objects on.
  * @err: A location to return an error or NULL.
  * ...: The attributes to match.
  * 
@@ -712,7 +810,7 @@
  * Return value: A list of the matching objects, which may be empty.  
  **/
 GList*
-gp11_session_find_objects (GP11Session *session, GError **err, ...)
+gp11_session_find_objects (GP11Session *self, GError **err, ...)
 {
 	GP11Attributes *attrs;
 	GList *results;
@@ -722,14 +820,14 @@
 	attrs = gp11_attributes_new_valist (va);
 	va_end (va);
 
-	results = gp11_session_find_objects_full (session, attrs, NULL, err);
+	results = gp11_session_find_objects_full (self, attrs, NULL, err);
 	gp11_attributes_unref (attrs);
 	return results;
 }
 
 /**
  * gp11_session_find_objects_full:
- * @session: The session to find objects on.
+ * @self: The session to find objects on.
  * @attrs: The attributes to match.
  * @cancellable: Optional cancellation object or NULL.
  * @err: A location to return an error or NULL.
@@ -740,21 +838,21 @@
  * Return value: A list of the matching objects, which may be empty.
  **/
 GList*
-gp11_session_find_objects_full (GP11Session *session, GP11Attributes *attrs, 
+gp11_session_find_objects_full (GP11Session *self, GP11Attributes *attrs, 
                                 GCancellable *cancellable, GError **err)
 {
 	FindObjects args = { GP11_ARGUMENTS_INIT, attrs, NULL, 0 };
 	GList *results = NULL;
 	
-	if (_gp11_call_sync (session, perform_find_objects, &args, cancellable, err)) 
-		results = objlist_from_handles (session, args.objects, args.n_objects);
+	if (_gp11_call_sync (self, perform_find_objects, &args, cancellable, err)) 
+		results = objlist_from_handles (self, args.objects, args.n_objects);
 	g_free (args.objects);
 	return results;
 }
 
 /**
  * gp11_session_find_objects_async:
- * @session: The session to find objects on.
+ * @self: The session to find objects on.
  * @attrs: The attributes to match.
  * @cancellable: Optional cancellation object or NULL.
  * @callback: Called when the operation completes.
@@ -764,11 +862,11 @@
  * return immediately and complete asynchronously.
  **/
 void
-gp11_session_find_objects_async (GP11Session *session, GP11Attributes *attrs, 
+gp11_session_find_objects_async (GP11Session *self, GP11Attributes *attrs, 
                                  GCancellable *cancellable, GAsyncReadyCallback callback, 
                                  gpointer user_data)
 {
-	FindObjects *args = _gp11_call_async_prep (session, session, perform_find_objects, 
+	FindObjects *args = _gp11_call_async_prep (self, self, perform_find_objects, 
 	                                           sizeof (*args), free_find_objects);
 	args->attrs = attrs;
 	gp11_attributes_ref (attrs);
@@ -777,7 +875,7 @@
 
 /**
  * gp11_session_find_objects_finish:
- * @session: The session to find objects on.
+ * @self: The session to find objects on.
  * @result: The attributes to match.
  * @err: A location to return an error.
  * 
@@ -786,14 +884,14 @@
  * Return value: A list of the matching objects, which may be empty.
  **/
 GList*
-gp11_session_find_objects_finish (GP11Session *session, GAsyncResult *result, GError **err)
+gp11_session_find_objects_finish (GP11Session *self, GAsyncResult *result, GError **err)
 {
 	FindObjects *args;
 	
 	if (!_gp11_call_basic_finish (result, err))
 		return NULL;
 	args = _gp11_call_arguments (result, FindObjects);
-	return objlist_from_handles (session, args->objects, args->n_objects);
+	return objlist_from_handles (self, args->objects, args->n_objects);
 }
 
 
@@ -855,7 +953,7 @@
 }
 
 static guchar*
-crypt_sync (GP11Session *session, GP11Object *key, GP11Mechanism *mech_args, const guchar *input, 
+crypt_sync (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args, const guchar *input, 
             gsize n_input, gsize *n_result, GCancellable *cancellable, GError **err,
             CK_C_EncryptInit init_func, CK_C_Encrypt complete_func)
 {
@@ -881,7 +979,7 @@
 	args.init_func = init_func;
 	args.complete_func = complete_func;
 	
-	if (!_gp11_call_sync (session, perform_crypt, &args, cancellable, err)) {
+	if (!_gp11_call_sync (self, perform_crypt, &args, cancellable, err)) {
 		g_free (args.result);
 		return NULL;
 	}
@@ -890,11 +988,11 @@
 }
 
 static void
-crypt_async (GP11Session *session, GP11Object *key, GP11Mechanism *mech_args, const guchar *input, 
+crypt_async (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args, const guchar *input, 
              gsize n_input, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data,
              CK_C_EncryptInit init_func, CK_C_Encrypt complete_func)
 {
-	Crypt *args = _gp11_call_async_prep (session, session, perform_crypt, sizeof (*args), free_crypt);
+	Crypt *args = _gp11_call_async_prep (self, self, perform_crypt, sizeof (*args), free_crypt);
 
 	g_return_if_fail (GP11_IS_OBJECT (key));
 	g_return_if_fail (mech_args);
@@ -919,12 +1017,12 @@
 }
 
 static guchar*
-crypt_finish (GP11Session *session, GAsyncResult *result, gsize *n_result, GError **err)
+crypt_finish (GP11Session *self, GAsyncResult *result, gsize *n_result, GError **err)
 {
 	Crypt *args;
 	guchar *res;
 	
-	if (!_gp11_call_basic_finish (session, result, err))
+	if (!_gp11_call_basic_finish (self, result, err))
 		return NULL;
 	args = _gp11_call_arguments (result, Crypt);
 	
@@ -938,25 +1036,25 @@
 }
 
 guchar*
-gp11_session_encrypt (GP11Session *session, GP11Object *key, gulong mech, const guchar *input, 
+gp11_session_encrypt (GP11Session *self, GP11Object *key, gulong mech, const guchar *input, 
                       gsize n_input, gsize *n_result, GError **err)
 {
 	GP11Mechanism mech_args = { mech, NULL, 0 };
-	return gp11_session_encrypt_full (session, key, &mech_args, input, n_input, n_result, NULL, err);
+	return gp11_session_encrypt_full (self, key, &mech_args, input, n_input, n_result, NULL, err);
 }
 
 guchar*
-gp11_session_encrypt_full (GP11Session *session, GP11Object *key, GP11Mechanism *mech_args,
+gp11_session_encrypt_full (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args,
                            const guchar *input, gsize n_input, gsize *n_result,
                            GCancellable *cancellable, GError **err)
 {
 	GP11Module *module = NULL;
 	guchar *ret;
 	
-	g_object_get (session, "module", &module, NULL);
+	g_object_get (self, "module", &module, NULL);
 	g_return_val_if_fail (module != NULL, NULL);
 
-	ret = crypt_sync (session, key, mech_args, input, n_input, n_result, cancellable, err, 
+	ret = crypt_sync (self, key, mech_args, input, n_input, n_result, cancellable, err, 
 	                  module->funcs->C_EncryptInit, module->funcs->C_Encrypt);
 	
 	g_object_unref (module);
@@ -964,117 +1062,117 @@
 }
 
 void
-gp11_session_encrypt_async (GP11Session *session, GP11Object *key, GP11Mechanism *mech_args,
+gp11_session_encrypt_async (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args,
                             const guchar *input, gsize n_input, GCancellable *cancellable,
                             GAsyncReadyCallback callback, gpointer user_data)
 {
 	GP11Module *module = NULL;
-	g_object_get (session, "module", &module, NULL);
+	g_object_get (self, "module", &module, NULL);
 	g_return_if_fail (module != NULL);
 
-	crypt_async (session, key, mech_args, input, n_input, cancellable, callback, user_data,
+	crypt_async (self, key, mech_args, input, n_input, cancellable, callback, user_data,
 	             module->funcs->C_EncryptInit, module->funcs->C_Encrypt);
 	
 	g_object_unref (module);
 }
 
 guchar*
-gp11_session_encrypt_finish (GP11Session *session, GAsyncResult *result, gsize *n_result,
+gp11_session_encrypt_finish (GP11Session *self, GAsyncResult *result, gsize *n_result,
                              GError **err)
 {
-	return crypt_finish (session, result, n_result, err);
+	return crypt_finish (self, result, n_result, err);
 }
 
 guchar*
-gp11_session_decrypt (GP11Session *session, GP11Object *key, gulong mech_type, const guchar *input,
+gp11_session_decrypt (GP11Session *self, GP11Object *key, gulong mech_type, const guchar *input,
                       gsize n_input, gsize *n_result, GError **err)
 {
 	GP11Mechanism mech_args = { mech_type, NULL, 0 };
-	return gp11_session_decrypt_full (session, key, &mech_args, input, n_input, n_result, NULL, err);
+	return gp11_session_decrypt_full (self, key, &mech_args, input, n_input, n_result, NULL, err);
 }
 
 guchar*
-gp11_session_decrypt_full (GP11Session *session, GP11Object *key, GP11Mechanism *mech_args,
+gp11_session_decrypt_full (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args,
                            const guchar *input, gsize n_input, gsize *n_result,
                            GCancellable *cancellable, GError **err)
 {
 	GP11Module *module = NULL;
 	guchar *ret;
 	
-	g_object_get (session, "module", &module, NULL);
+	g_object_get (self, "module", &module, NULL);
 	g_return_val_if_fail (module != NULL, NULL);
 
-	ret = crypt_sync (session, key, mech_args, input, n_input, n_result, cancellable, err,
+	ret = crypt_sync (self, key, mech_args, input, n_input, n_result, cancellable, err,
 	                  module->funcs->C_DecryptInit, module->funcs->C_Decrypt);
 	g_object_unref (module);
 	return ret;
 }
 
 void
-gp11_session_decrypt_async (GP11Session *session, GP11Object *key, GP11Mechanism *mech_args,
+gp11_session_decrypt_async (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args,
                             const guchar *input, gsize n_input, GCancellable *cancellable,
                             GAsyncReadyCallback callback, gpointer user_data)
 {
 	GP11Module *module = NULL;
-	g_object_get (session, "module", &module, NULL);
+	g_object_get (self, "module", &module, NULL);
 	g_return_if_fail (module != NULL);
 
-	crypt_async (session, key, mech_args, input, n_input, cancellable, callback, user_data,
+	crypt_async (self, key, mech_args, input, n_input, cancellable, callback, user_data,
 	             module->funcs->C_DecryptInit, module->funcs->C_Decrypt);
 	g_object_unref (module);
 }
 
 guchar*
-gp11_session_decrypt_finish (GP11Session *session, GAsyncResult *result,
+gp11_session_decrypt_finish (GP11Session *self, GAsyncResult *result,
                              gsize *n_result, GError **err)
 {
-	return crypt_finish (session, result, n_result, err);
+	return crypt_finish (self, result, n_result, err);
 }
 
 guchar*
-gp11_session_sign (GP11Session *session, GP11Object *key, gulong mech_type, const guchar *input, 
+gp11_session_sign (GP11Session *self, GP11Object *key, gulong mech_type, const guchar *input, 
                    gsize n_input, gsize *n_result, GError **err)
 {
 	GP11Mechanism mech_args = { mech_type, NULL, 0 };
-	return gp11_session_sign_full (session, key, &mech_args, input, n_input, n_result, NULL, err);
+	return gp11_session_sign_full (self, key, &mech_args, input, n_input, n_result, NULL, err);
 }
 
 guchar*
-gp11_session_sign_full (GP11Session *session, GP11Object *key, GP11Mechanism *mech_args,
+gp11_session_sign_full (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args,
                         const guchar *input, gsize n_input, gsize *n_result,
                         GCancellable *cancellable, GError **err)
 {
 	GP11Module *module = NULL;
 	guchar *ret;
 	
-	g_object_get (session, "module", &module, NULL);
+	g_object_get (self, "module", &module, NULL);
 	g_return_val_if_fail (module != NULL, NULL);
 
-	return crypt_sync (session, key, mech_args, input, n_input, n_result, cancellable, err,
+	return crypt_sync (self, key, mech_args, input, n_input, n_result, cancellable, err,
 	                   module->funcs->C_SignInit, module->funcs->C_Sign);
 	g_object_unref (module);
 	return ret;
 }
 
 void
-gp11_session_sign_async (GP11Session *session, GP11Object *key, GP11Mechanism *mech_args,
+gp11_session_sign_async (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args,
                          const guchar *input, gsize n_input, GCancellable *cancellable,
                          GAsyncReadyCallback callback, gpointer user_data)
 {
 	GP11Module *module = NULL;
-	g_object_get (session, "module", &module, NULL);
+	g_object_get (self, "module", &module, NULL);
 	g_return_if_fail (module != NULL);
 
-	crypt_async (session, key, mech_args, input, n_input, cancellable, callback, user_data,
+	crypt_async (self, key, mech_args, input, n_input, cancellable, callback, user_data,
 	             module->funcs->C_SignInit, module->funcs->C_Sign);
 	g_object_unref (module);
 }
 
 guchar*
-gp11_session_sign_finish (GP11Session *session, GAsyncResult *result, 
+gp11_session_sign_finish (GP11Session *self, GAsyncResult *result, 
                           gsize *n_result, GError **err)
 {
-	return crypt_finish (session, result, n_result, err);	
+	return crypt_finish (self, result, n_result, err);	
 }
 
 
@@ -1115,16 +1213,16 @@
 }
 
 gboolean
-gp11_session_verify (GP11Session *session, GP11Object *key, gulong mech_type, const guchar *input,
+gp11_session_verify (GP11Session *self, GP11Object *key, gulong mech_type, const guchar *input,
                      gsize n_input, const guchar *signature, gsize n_signature, GError **err)
 {
 	GP11Mechanism mech_args = { mech_type, NULL, 0 };
-	return gp11_session_verify_full (session, key, &mech_args, input, n_input, 
+	return gp11_session_verify_full (self, key, &mech_args, input, n_input, 
 	                                 signature, n_signature, NULL, err);	
 }
 
 gboolean
-gp11_session_verify_full (GP11Session *session, GP11Object *key, GP11Mechanism *mech_args,
+gp11_session_verify_full (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args,
                           const guchar *input, gsize n_input, const guchar *signature,
                           gsize n_signature, GCancellable *cancellable, GError **err)
 {
@@ -1147,16 +1245,16 @@
 	args.signature = (guchar*)signature;
 	args.n_signature = n_signature;
 
-	return _gp11_call_sync (session, perform_verify, &args, cancellable, err);
+	return _gp11_call_sync (self, perform_verify, &args, cancellable, err);
 }
 
 void
-gp11_session_verify_async (GP11Session *session, GP11Object *key, GP11Mechanism *mech_args,
+gp11_session_verify_async (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args,
                            const guchar *input, gsize n_input, const guchar *signature,
                            gsize n_signature, GCancellable *cancellable,
                            GAsyncReadyCallback callback, gpointer user_data)
 {
-	Verify *args = _gp11_call_async_prep (session, session, perform_verify, sizeof (*args), free_verify);
+	Verify *args = _gp11_call_async_prep (self, self, perform_verify, sizeof (*args), free_verify);
 
 	g_return_if_fail (GP11_IS_OBJECT (key));
 	g_return_if_fail (mech_args);
@@ -1178,9 +1276,9 @@
 }
 
 gboolean
-gp11_session_verify_finish (GP11Session *session, GAsyncResult *result, GError **err)
+gp11_session_verify_finish (GP11Session *self, GAsyncResult *result, GError **err)
 {
-	return _gp11_call_basic_finish (session, result, err);
+	return _gp11_call_basic_finish (self, result, err);
 }
 
 #endif /* UNTESTED */

Modified: trunk/gp11/gp11-slot.c
==============================================================================
--- trunk/gp11/gp11-slot.c	(original)
+++ trunk/gp11/gp11-slot.c	Sat Dec 27 18:29:23 2008
@@ -46,7 +46,14 @@
 	LAST_SIGNAL
 };
 
+typedef struct _GP11SlotData {
+	GP11Module *module;
+	CK_SLOT_ID handle;
+} GP11SlotData;
+
 typedef struct _GP11SlotPrivate {
+	GP11SlotData data;
+	GStaticMutex mutex;
 	gboolean auto_login;
 	GHashTable *open_sessions;
 	GP11TokenInfo *token_info;
@@ -54,8 +61,8 @@
 
 G_DEFINE_TYPE (GP11Slot, gp11_slot, G_TYPE_OBJECT);
 
-#define GP11_SLOT_GET_PRIVATE(o) \
-      (G_TYPE_INSTANCE_GET_PRIVATE((o), GP11_TYPE_SLOT, GP11SlotPrivate))
+#define GP11_SLOT_GET_DATA(o) \
+      (G_TYPE_INSTANCE_GET_PRIVATE((o), GP11_TYPE_SLOT, GP11SlotData))
 
 typedef struct _SessionPool {
 	gulong flags;
@@ -102,242 +109,246 @@
  * HELPERS
  */
 
+static guint
+ulong_hash (gconstpointer v)
+{
+	const signed char *p = v;
+	guint32 i, h = *p;
+
+	for(i = 0; i < sizeof (gulong); ++i)
+		h = (h << 5) - h + *(p++);
+
+	return h;
+}
+
+static gboolean
+ulong_equal (gconstpointer v1, gconstpointer v2)
+{
+	return *((const gulong*)v1) == *((const gulong*)v2);
+}
+
 static void
 close_session (GP11Module *module, CK_SESSION_HANDLE handle)
 {
+	CK_FUNCTION_LIST_PTR funcs;
 	CK_RV rv; 
 	
 	g_return_if_fail (GP11_IS_MODULE (module));
-	g_return_if_fail (module->funcs);
-	rv = (module->funcs->C_CloseSession) (handle);
+	
+	g_object_ref (module);
+	
+	funcs = gp11_module_get_function_list (module);
+	g_return_if_fail (funcs);
+	
+	rv = (funcs->C_CloseSession) (handle);
 	if (rv != CKR_OK) {
 		g_warning ("couldn't close session properly: %s",
 		           gp11_message_from_rv (rv));
 	}
+	
+	g_object_unref (module);
 }
 
-static void
-free_session_pool (gpointer p)
+static GP11SlotPrivate*
+lock_private (gpointer obj)
 {
-	SessionPool *pool = p;
-	guint i;
+	GP11SlotPrivate *pv;
+	GP11Slot *self;
 	
-	for(i = 0; i < pool->sessions->len; ++i)
-		close_session (pool->module, g_array_index(pool->sessions, CK_SESSION_HANDLE, i));
-	g_array_free(pool->sessions, TRUE);
-	g_free (pool);
+	g_assert (GP11_IS_SLOT (obj));
+	self = GP11_SLOT (obj);
+	
+	g_object_ref (self);
+	
+	pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GP11_TYPE_SLOT, GP11SlotPrivate);
+	g_static_mutex_lock (&pv->mutex);
+	
+	return pv;
 }
 
-#ifdef UNUSED
-
 static void
-foreach_count_sessions (gpointer key, gpointer value, gpointer user_data)
+unlock_private (gpointer obj, GP11SlotPrivate *pv)
 {
-	SessionPool *pool = value;
-	guint *result = user_data;
-	*result += pool->sessions->len;
-}
+	GP11Slot *self;
 
-static guint
-count_session_table (GP11Slot *slot, guint flags)
-{
-	GP11SlotPrivate *pv = GP11_SLOT_GET_PRIVATE (slot);
-	guint result = 0;
+	g_assert (pv);
+	g_assert (GP11_IS_SLOT (obj));
 	
-	if (!pv->open_sessions)
-		return 0;
+	self = GP11_SLOT (obj);
 	
-	g_hash_table_foreach (pv->open_sessions, foreach_count_sessions, &result);
-	return result;
+	g_assert (G_TYPE_INSTANCE_GET_PRIVATE (self, GP11_TYPE_SLOT, GP11SlotPrivate) == pv);
+	
+	g_static_mutex_unlock (&pv->mutex);
+	g_object_unref (self);
 }
 
-#endif /* UNUSED */
-
 static void
-push_session_table (GP11Slot *slot, gulong flags, CK_SESSION_HANDLE handle)
+free_session_pool (gpointer p)
 {
-	GP11SlotPrivate *pv = GP11_SLOT_GET_PRIVATE (slot);
-	SessionPool *pool;
-	
-	if (!pv->open_sessions) {
-		close_session (slot->module, handle);
-		return;
-	}
+	SessionPool *pool = p;
+	guint i;
 	
+	for(i = 0; i < pool->sessions->len; ++i)
+		close_session (pool->module, g_array_index(pool->sessions, CK_SESSION_HANDLE, i));
+	g_array_free(pool->sessions, TRUE);
+	g_free (pool);
+}
+
+static gboolean
+push_session_table (GP11SlotPrivate *pv, gulong flags, CK_SESSION_HANDLE handle)
+{
+	SessionPool *pool;
+
 	g_assert (handle);
-	g_assert (GP11_IS_MODULE (slot->module));
-	
+	g_assert (GP11_IS_MODULE (pv->data.module));
+
+	if (pv->open_sessions == NULL)
+		return FALSE;
+		
 	pool = g_hash_table_lookup (pv->open_sessions, &flags);
 	if (!pool) {
 		pool = g_new0 (SessionPool, 1);
 		pool->flags = flags;
-		pool->module = slot->module; /* weak ref */
+		pool->module = pv->data.module; /* weak ref */
 		pool->sessions = g_array_new (FALSE, TRUE, sizeof (CK_SESSION_HANDLE));
 		g_hash_table_insert (pv->open_sessions, g_memdup (&flags, sizeof (flags)), pool);
 	}
 	
 	g_assert (pool->flags == flags);
 	g_array_append_val (pool->sessions, handle);
+	return TRUE;
 }
 
 static CK_SESSION_HANDLE
-pop_session_table (GP11Slot *slot, gulong flags)
+pop_session_table (GP11SlotPrivate *pv, gulong flags)
 {
-	GP11SlotPrivate *pv = GP11_SLOT_GET_PRIVATE (slot);
-	CK_SESSION_HANDLE result;
+	CK_SESSION_HANDLE result = 0;
 	SessionPool *pool;
-	
-	if (!pv->open_sessions)
-		return 0;
-	
-	g_assert (GP11_IS_MODULE (slot->module));
-	
-	pool = g_hash_table_lookup (pv->open_sessions, &flags);
-	if (!pool)
-		return 0;
-	
-	g_assert (pool->sessions->len > 0);
-	result = g_array_index (pool->sessions, CK_SESSION_HANDLE, pool->sessions->len - 1);
-	g_assert (result != 0);
-	g_array_remove_index_fast (pool->sessions, pool->sessions->len - 1);
-	if (!pool->sessions->len)
-		g_hash_table_remove(pv->open_sessions, &flags);
+
+	g_return_val_if_fail (pv, 0);
+
+
+	g_assert (GP11_IS_MODULE (pv->data.module));
+
+	if (pv->open_sessions) {
+		pool = g_hash_table_lookup (pv->open_sessions, &flags);
+		if (pool) {
+			g_assert (pool->sessions->len > 0);
+			result = g_array_index (pool->sessions, CK_SESSION_HANDLE, pool->sessions->len - 1);
+			g_assert (result != 0);
+			g_array_remove_index_fast (pool->sessions, pool->sessions->len - 1);
+			if (!pool->sessions->len)
+				g_hash_table_remove(pv->open_sessions, &flags);
+		}
+	}
 
 	return result;
 }
 
 static void
-destroy_session_table (GP11Slot *slot)
+destroy_session_table (GP11SlotPrivate *pv)
 {
-	GP11SlotPrivate *pv = GP11_SLOT_GET_PRIVATE (slot);
 	if (pv->open_sessions)
 		g_hash_table_unref (pv->open_sessions);
 	pv->open_sessions = NULL;
 }
 
-static guint
-ulong_hash (gconstpointer v)
-{
-	// TODO: I'm sure there's a better gulong hash
-	const signed char *p = v;
-	guint32 i, h = *p;
-
-	for(i = 0; i < sizeof (gulong); ++i)
-		h = (h << 5) - h + *(p++);
-
-	return h;
-}
-
-static gboolean
-ulong_equal (gconstpointer v1, gconstpointer v2)
-{
-	return *((const gulong*)v1) == *((const gulong*)v2);
-}
-
 static void
-create_session_table (GP11Slot *slot)
+create_session_table (GP11SlotPrivate *pv)
 {
-	GP11SlotPrivate *pv = GP11_SLOT_GET_PRIVATE (slot);
 	if (!pv->open_sessions)
 		pv->open_sessions = g_hash_table_new_full (ulong_hash, ulong_equal, g_free, free_session_pool);
 }
 
-static void
-reuse_session_handle (GP11Session *session, GP11Slot *slot)
+static gboolean
+reuse_session_handle (GP11Session *session, CK_SESSION_HANDLE handle, GP11Slot *self)
 {
+	GP11SlotData *data = GP11_SLOT_GET_DATA (self);
+	GP11SlotPrivate *pv;
+	CK_FUNCTION_LIST_PTR funcs;
 	CK_SESSION_INFO info;
-	gulong *flags;
+	gboolean handled = FALSE;
 	CK_RV rv;
 	
-	g_return_if_fail (GP11_IS_SESSION (session));
-	g_return_if_fail (GP11_IS_SLOT (slot));
-	g_return_if_fail (GP11_IS_MODULE (slot->module));
-	g_return_if_fail (session->handle != 0);
+	g_return_val_if_fail (GP11_IS_SESSION (session), FALSE);
+	g_return_val_if_fail (GP11_IS_SLOT (self), FALSE);
 	
+	funcs = gp11_module_get_function_list (data->module);
+	g_return_val_if_fail (funcs, FALSE);
+
 	/* Get the session info so we know where to categorize this */
-	rv = (slot->module->funcs->C_GetSessionInfo) (session->handle, &info);
-	
-	/* An already closed session, we don't want to bother with */
-	if (rv == CKR_SESSION_CLOSED || rv == CKR_SESSION_HANDLE_INVALID) {
-		session->handle = 0;
-		return;
-	}
+	rv = (funcs->C_GetSessionInfo) (handle, &info);
+
+	if (rv == CKR_OK) {
 	
-	/* A strange session, let it go to be closed somewhere else */
-	if (rv != CKR_OK)
-		return;
+		/* Keep this one around for later use */
+		pv = lock_private (self);
+		
+		{
+			handled = push_session_table (pv, info.flags, handle);
+		}
+		
+		unlock_private (self, pv);
 	
-	/* 
-	 * Get the flags that this session was opened with originally, and
-	 * check them against the session's current flags. If they're no
-	 * longer present, then don't reuse this session.
-	 */
-	flags = g_object_get_data (G_OBJECT (session), "gp11-open-session-flags");
-	g_return_if_fail (flags);
-	if ((*flags & info.flags) != *flags)
-		return;
+	} else {
 	
-	/* Keep this one around for later use */
-	push_session_table (slot, *flags, session->handle);
-	session->handle = 0;
+		/* An already closed session, we don't want to bother with */
+		if (rv == CKR_SESSION_CLOSED || rv == CKR_SESSION_HANDLE_INVALID)
+			handled = TRUE;
+	}
+
+	return handled;
 }
 
 static GP11Session*
-make_session_object (GP11Slot *slot, gulong flags, CK_SESSION_HANDLE handle)
+make_session_object (GP11Slot *self, gulong flags, CK_SESSION_HANDLE handle)
 {
 	GP11Session *session;
-	
+
 	g_return_val_if_fail (handle != 0, NULL);
-	session = gp11_session_from_handle (slot, handle);
-	g_return_val_if_fail (session != NULL, NULL);
-	
-	/* Session keeps a reference to us, so this is safe */
-	g_signal_connect (session, "discard-handle", G_CALLBACK (reuse_session_handle), slot);
 
-	/* Mark the flags on the session for later looking up */
-	g_object_set_data_full (G_OBJECT (session), "gp11-open-session-flags", 
-	                        g_memdup (&flags, sizeof (flags)), g_free);
+	g_object_ref (self);
+	
+		session = gp11_session_from_handle (self, handle);
+		g_return_val_if_fail (session != NULL, NULL);
+	
+		/* Session keeps a reference to us, so this is safe */
+		g_signal_connect (session, "discard-handle", G_CALLBACK (reuse_session_handle), self);
+	
+	g_object_unref (self);
 	
 	return session;
 }
 
-static void 
-ensure_token_info (GP11Slot *slot)
-{
-	GP11SlotPrivate *pv = GP11_SLOT_GET_PRIVATE (slot);
-	if (!pv->token_info) 
-		pv->token_info = gp11_slot_get_token_info (slot);
-}
-
 /* ----------------------------------------------------------------------------
  * OBJECT
  */
 
 static void
-gp11_slot_init (GP11Slot *slot)
+gp11_slot_init (GP11Slot *self)
 {
-	
+	GP11SlotPrivate *pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GP11_TYPE_SLOT, GP11SlotPrivate);
+	g_static_mutex_init (&pv->mutex);
 }
 
 static void
 gp11_slot_get_property (GObject *obj, guint prop_id, GValue *value, 
                         GParamSpec *pspec)
 {
-	GP11SlotPrivate *pv = GP11_SLOT_GET_PRIVATE (obj);
-	GP11Slot *slot = GP11_SLOT (obj);
-
+	GP11Slot *self = GP11_SLOT (obj);
+	
 	switch (prop_id) {
 	case PROP_MODULE:
-		g_value_set_object (value, slot->module);
+		g_value_take_object (value, gp11_slot_get_module (self));
 		break;
 	case PROP_HANDLE:
-		g_value_set_uint (value, slot->handle);
+		g_value_set_ulong (value, gp11_slot_get_handle (self));
 		break;
 	case PROP_AUTO_LOGIN:
-		g_value_set_boolean (value, pv->auto_login);
+		g_value_set_boolean (value, gp11_slot_get_auto_login (self));
 		break;
 	case PROP_REUSE_SESSIONS:
-		g_value_set_boolean (value, pv->open_sessions != NULL);
+		g_value_set_boolean (value, gp11_slot_get_reuse_sessions (self));
 		break;
 	}
 }
@@ -346,28 +357,27 @@
 gp11_slot_set_property (GObject *obj, guint prop_id, const GValue *value, 
                         GParamSpec *pspec)
 {
-	GP11SlotPrivate *pv = GP11_SLOT_GET_PRIVATE (obj);
-	GP11Slot *slot = GP11_SLOT (obj);
+	GP11SlotData *data = GP11_SLOT_GET_DATA (obj);
+	GP11Slot *self = GP11_SLOT (obj);
+
+	/* All writes to data members below, happen only during construct phase */
 
 	switch (prop_id) {
 	case PROP_MODULE:
-		g_return_if_fail (!slot->module);
-		slot->module = g_value_get_object (value);
-		g_return_if_fail (slot->module);
-		g_object_ref (slot->module);
+		g_assert (!data->module);
+		data->module = g_value_get_object (value);
+		g_assert (data->module);
+		g_object_ref (data->module);
 		break;
 	case PROP_HANDLE:
-		g_return_if_fail (!slot->handle);
-		slot->handle = g_value_get_uint (value);
+		g_assert (!data->handle);
+		data->handle = g_value_get_ulong (value);
 		break;
 	case PROP_AUTO_LOGIN:
-		pv->auto_login = g_value_get_boolean (value);
+		gp11_slot_set_auto_login (self, g_value_get_boolean (value));
 		break;
 	case PROP_REUSE_SESSIONS:
-		if (g_value_get_boolean (value))
-			create_session_table (slot);
-		else
-			destroy_session_table (slot);
+		gp11_slot_set_reuse_sessions (self, g_value_get_boolean (value));
 		break;
 	}
 }
@@ -375,14 +385,14 @@
 static void
 gp11_slot_dispose (GObject *obj)
 {
-	GP11Slot *slot = GP11_SLOT (obj);
-
-	/* Need to do this before the module goes away */
-	destroy_session_table (slot);
+	GP11SlotPrivate *pv = lock_private (obj);
+	
+	{
+		/* Need to do this before the module goes away */
+		destroy_session_table (pv);
+	}
 
-	if (slot->module)
-		g_object_unref (slot->module);
-	slot->module = NULL;
+	unlock_private (obj, pv);
 
 	G_OBJECT_CLASS (gp11_slot_parent_class)->dispose (obj);
 }
@@ -390,10 +400,22 @@
 static void
 gp11_slot_finalize (GObject *obj)
 {
-	GP11Slot *slot = GP11_SLOT (obj);
+	GP11SlotPrivate *pv = G_TYPE_INSTANCE_GET_PRIVATE (obj, GP11_TYPE_SLOT, GP11SlotPrivate);
+	GP11SlotData *data = GP11_SLOT_GET_DATA (obj);
+	
+	data->handle = 0;
+	
+	g_assert (!pv->open_sessions);
+	
+	if (data->module)
+		g_object_unref (data->module);
+	data->module = NULL;
+		
+	if (pv->token_info)
+		gp11_token_info_free (pv->token_info);
+	pv->token_info = NULL;	
 
-	g_assert (slot->module == NULL);
-	slot->handle = 0;
+	g_static_mutex_free (&pv->mutex);
 	
 	G_OBJECT_CLASS (gp11_slot_parent_class)->finalize (obj);
 }
@@ -415,8 +437,8 @@
 		                     GP11_TYPE_MODULE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property (gobject_class, PROP_HANDLE,
-		g_param_spec_uint ("handle", "Handle", "PKCS11 Slot ID",
-		                   0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+		g_param_spec_ulong ("handle", "Handle", "PKCS11 Slot ID",
+		                   0, G_MAXULONG, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property (gobject_class, PROP_AUTO_LOGIN,
 		g_param_spec_boolean ("auto-login", "Auto Login", "Auto Login to Token when necessary",
@@ -439,29 +461,41 @@
  */
 
 gboolean 
-_gp11_slot_token_authentication (GP11Slot *slot, gchar **password)
+_gp11_slot_token_authentication (GP11Slot *self, gchar **password)
 {
-	GP11SlotPrivate *pv = GP11_SLOT_GET_PRIVATE (slot);
+	GP11SlotPrivate *pv = lock_private (self);
+	gboolean emit_signal = FALSE;
 	gboolean ret = FALSE;
-	
-	g_return_val_if_fail (GP11_IS_SLOT (slot), FALSE);
+
+	g_return_val_if_fail (GP11_IS_SLOT (self), FALSE);
 	g_return_val_if_fail (password, FALSE);
-	
-	if (!pv->auto_login)
-		return FALSE;
 
-	/* 
-	 * If it's a protected authentication path style token, then 
-	 * we don't prompt here, the hardware/software is expected
-	 * to prompt the user in some other way.
-	 */
-	ensure_token_info (slot);
-	if (pv->token_info && (pv->token_info->flags & CKF_PROTECTED_AUTHENTICATION_PATH)) {
-		*password = NULL;
-		return TRUE;
+	{
+		if (pv->auto_login) {
+			
+			/* 
+			 * If it's a protected authentication path style token, then 
+			 * we don't prompt here, the hardware/software is expected
+			 * to prompt the user in some other way.
+			 */
+			
+			if (!pv->token_info) 
+				pv->token_info = gp11_slot_get_token_info (self);
+
+			if (pv->token_info && (pv->token_info->flags & CKF_PROTECTED_AUTHENTICATION_PATH)) {
+				*password = NULL;
+				ret = TRUE;
+			} else {
+				emit_signal = TRUE;
+			}
+		}
 	}
-		
-	g_signal_emit (slot, signals[AUTHENTICATE_TOKEN], 0, password, &ret);
+	
+	unlock_private (self, pv);
+
+	if (emit_signal)
+		g_signal_emit (self, signals[AUTHENTICATE_TOKEN], 0, password, &ret);
+
 	return ret;
 }
 
@@ -519,22 +553,40 @@
 
 /**
  * gp11_slot_get_handle:
- * @slot: The slot to get the handle of.
+ * @self: The slot to get the handle of.
  * 
  * Get the raw PKCS#11 handle of a slot.
  * 
  * Return value: The raw handle.
  **/
 CK_SLOT_ID
-gp11_slot_get_handle (GP11Slot *slot)
+gp11_slot_get_handle (GP11Slot *self)
+{
+	GP11SlotData *data = GP11_SLOT_GET_DATA (self);
+	g_return_val_if_fail (GP11_IS_SLOT (self), (CK_SLOT_ID)-1);
+	return data->handle;
+}
+
+/**
+ * gp11_slot_get_module:
+ * @self: The slot to get the module for.
+ * 
+ * Get the module that this slot is on.
+ * 
+ * Return value: The module, you must unreference this after you're done with it.
+ */
+GP11Module*
+gp11_slot_get_module (GP11Slot *self)
 {
-	g_return_val_if_fail (GP11_IS_SLOT (slot), (CK_SLOT_ID)-1);
-	return slot->handle;
+	GP11SlotData *data = GP11_SLOT_GET_DATA (self);
+	g_return_val_if_fail (GP11_IS_SLOT (self), NULL);
+	g_return_val_if_fail (GP11_IS_MODULE (data->module), NULL);
+	return g_object_ref (data->module);
 }
 
 /**
  * gp11_slot_get_reuse_sessions:
- * @slot: The slot to get setting from.
+ * @self: The slot to get setting from.
  * 
  * Get the reuse sessions setting. When this is set, sessions
  * will be pooled and reused if their flags match when 
@@ -543,30 +595,51 @@
  * Return value: Whether reusing sessions or not.
  **/
 gboolean
-gp11_slot_get_reuse_sessions (GP11Slot *slot)
+gp11_slot_get_reuse_sessions (GP11Slot *self)
 {
-	gboolean reuse = FALSE;
-	g_object_get (slot, "reuse-sessions", &reuse, NULL);
-	return reuse;
+	GP11SlotPrivate *pv = lock_private (self);
+	gboolean ret;
+	
+	g_return_val_if_fail (pv, FALSE);
+	
+	{
+		ret = pv->open_sessions != NULL;
+	}
+	
+	unlock_private (self, pv);
+
+	return ret;
 }
 
 /**
  * gp11_slot_set_reuse_sessions:
- * @slot: The slot to set the setting on.
+ * @self: The slot to set the setting on.
  * @reuse: Whether to reuse sessions or not.
  * 
  * When this is set, sessions will be pooled and reused
  * if their flags match when gp11_slot_open_session() is called.
  **/
 void
-gp11_slot_set_reuse_sessions (GP11Slot *slot, gboolean reuse)
+gp11_slot_set_reuse_sessions (GP11Slot *self, gboolean reuse)
 {
-	g_object_set (slot, "reuse-sessions", reuse, NULL);
+	GP11SlotPrivate *pv = lock_private (self);
+
+	g_return_if_fail (pv);
+	
+	{
+		if (reuse)
+			create_session_table (pv);
+		else
+			destroy_session_table (pv);
+	}
+	
+	unlock_private (self, pv);
+	g_object_notify (G_OBJECT (self), "reuse-sessions");
 }
 
 /**
  * gp11_slot_get_auto_login:
- * @slot: The slot to get setting from.
+ * @self: The slot to get setting from.
  * 
  * Get the auto login setting. When this is set, this slot 
  * will emit the 'authenticate-token' signal when a session
@@ -575,16 +648,25 @@
  * Return value: Whether auto login or not.
  **/
 gboolean
-gp11_slot_get_auto_login (GP11Slot *slot)
+gp11_slot_get_auto_login (GP11Slot *self)
 {
-	gboolean auto_login = FALSE;
-	g_object_get (slot, "auto-login", &auto_login, NULL);
-	return auto_login;
+	GP11SlotPrivate *pv = lock_private (self);
+	gboolean ret;
+	
+	g_return_val_if_fail (pv, FALSE);
+	
+	{
+		ret = pv->auto_login;
+	}
+	
+	unlock_private (self, pv);
+
+	return ret;
 }
 
 /**
  * gp11_slot_set_auto_login:
- * @slot: The slot to set the setting on.
+ * @self: The slot to set the setting on.
  * @auto_login: Whether auto login or not.
  * 
  * When this is set, this slot 
@@ -592,14 +674,23 @@
  * requires authentication.
  **/
 void
-gp11_slot_set_auto_login (GP11Slot *slot, gboolean auto_login)
+gp11_slot_set_auto_login (GP11Slot *self, gboolean auto_login)
 {
-	g_object_set (slot, "auto-login", auto_login, NULL);
+	GP11SlotPrivate *pv = lock_private (self);
+
+	g_return_if_fail (pv);
+	
+	{
+		pv->auto_login = auto_login;
+	}
+	
+	unlock_private (self, pv);
+	g_object_notify (G_OBJECT (self), "auto-login");
 }
 
 /**
  * gp11_slot_get_info:
- * @slot: The slot to get info for.
+ * @self: The slot to get info for.
  * 
  * Get the information for this slot.
  * 
@@ -607,18 +698,28 @@
  * to release it.
  **/
 GP11SlotInfo*
-gp11_slot_get_info (GP11Slot *slot)
+gp11_slot_get_info (GP11Slot *self)
 {
+	CK_SLOT_ID handle = (CK_SLOT_ID)-1;
+	GP11Module *module = NULL;
+	CK_FUNCTION_LIST_PTR funcs;
 	GP11SlotInfo *slotinfo;
 	CK_SLOT_INFO info;
 	CK_RV rv;
 	
-	g_return_val_if_fail (GP11_IS_SLOT (slot), NULL);
-	g_return_val_if_fail (GP11_IS_MODULE (slot->module), NULL);
-	g_return_val_if_fail (slot->module->funcs, NULL);
+	g_return_val_if_fail (GP11_IS_SLOT (self), NULL);
+	
+	g_object_get (self, "module", &module, "handle", &handle, NULL);
+	g_return_val_if_fail (GP11_IS_MODULE (module), NULL);
+	
+	funcs = gp11_module_get_function_list (module);
+	g_return_val_if_fail (funcs, NULL);
 	
 	memset (&info, 0, sizeof (info));
-	rv = (slot->module->funcs->C_GetSlotInfo) (slot->handle, &info);
+	rv = (funcs->C_GetSlotInfo) (handle, &info);
+	
+	g_object_unref (module);
+	
 	if (rv != CKR_OK) {
 		g_warning ("couldn't get slot info: %s", gp11_message_from_rv (rv));
 		return NULL;
@@ -640,7 +741,7 @@
 
 /**
  * gp11_slot_get_token_info:
- * @slot: The slot to get info for.
+ * @self: The slot to get info for.
  * 
  * Get the token information for this slot.
  * 
@@ -648,20 +749,30 @@
  * to release it.
  **/
 GP11TokenInfo*
-gp11_slot_get_token_info (GP11Slot *slot)
+gp11_slot_get_token_info (GP11Slot *self)
 {
+	CK_SLOT_ID handle = (CK_SLOT_ID)-1;
+	CK_FUNCTION_LIST_PTR funcs;
+	GP11Module *module = NULL;
 	GP11TokenInfo *tokeninfo;
 	CK_TOKEN_INFO info;
 	gchar *string;
 	struct tm tm;
 	CK_RV rv;
 	
-	g_return_val_if_fail (GP11_IS_SLOT (slot), NULL);
-	g_return_val_if_fail (GP11_IS_MODULE (slot->module), NULL);
-	g_return_val_if_fail (slot->module->funcs, NULL);
+	g_return_val_if_fail (GP11_IS_SLOT (self), NULL);
+
+	g_object_get (self, "module", &module, "handle", &handle, NULL);
+	g_return_val_if_fail (GP11_IS_MODULE (module), NULL);
+	
+	funcs = gp11_module_get_function_list (module);
+	g_return_val_if_fail (funcs, NULL);
 	
 	memset (&info, 0, sizeof (info));
-	rv = (slot->module->funcs->C_GetTokenInfo) (slot->handle, &info);
+	rv = (funcs->C_GetTokenInfo) (handle, &info);
+	
+	g_object_unref (module);
+	
 	if (rv != CKR_OK) {
 		g_warning ("couldn't get slot info: %s", gp11_message_from_rv (rv));
 		return NULL;
@@ -706,7 +817,7 @@
 
 /**
  * gp11_slot_get_mechanisms:
- * @slot: The slot to get mechanisms for.
+ * @self: The slot to get mechanisms for.
  * 
  * Get the available mechanisms for this slot.
  * 
@@ -714,33 +825,42 @@
  * gp11_mechanisms_free() when done with this.
  **/
 GP11Mechanisms*
-gp11_slot_get_mechanisms (GP11Slot *slot)
+gp11_slot_get_mechanisms (GP11Slot *self)
 {
+	CK_SLOT_ID handle = (CK_SLOT_ID)-1;
+	CK_FUNCTION_LIST_PTR funcs;
+	GP11Module *module = NULL;
 	CK_MECHANISM_TYPE_PTR mech_list;
 	CK_ULONG count, i;
 	GP11Mechanisms *result;
 	CK_RV rv;
 	
-	g_return_val_if_fail (GP11_IS_SLOT (slot), NULL);
-	g_return_val_if_fail (GP11_IS_MODULE (slot->module), NULL);
-	g_return_val_if_fail (slot->module->funcs, NULL);
+	g_return_val_if_fail (GP11_IS_SLOT (self), NULL);
 
-	rv = (slot->module->funcs->C_GetMechanismList) (slot->handle, NULL, &count);
+	g_object_get (self, "module", &module, "handle", &handle, NULL);
+	g_return_val_if_fail (GP11_IS_MODULE (module), NULL);
+
+	funcs = gp11_module_get_function_list (module);
+	g_return_val_if_fail (funcs, NULL);
+	
+	rv = (funcs->C_GetMechanismList) (handle, NULL, &count);
 	if (rv != CKR_OK) {
 		g_warning ("couldn't get mechanism count: %s", gp11_message_from_rv (rv));
-		return NULL;
+		count = 0;
+	} else {
+		mech_list = g_new (CK_MECHANISM_TYPE, count);
+		rv = (funcs->C_GetMechanismList) (handle, mech_list, &count);
+		if (rv != CKR_OK) {
+			g_warning ("couldn't get mechanism list: %s", gp11_message_from_rv (rv));
+			g_free (mech_list);
+			count = 0;
+		}
 	}
 	
-	if (!count)
-		return NULL;
+	g_object_unref (module);
 	
-	mech_list = g_new (CK_MECHANISM_TYPE, count);
-	rv = (slot->module->funcs->C_GetMechanismList) (slot->handle, mech_list, &count);
-	if (rv != CKR_OK) {
-		g_warning ("couldn't get mechanism list: %s", gp11_message_from_rv (rv));
-		g_free (mech_list);
+	if (!count)
 		return NULL;
-	}
 	
 	result = g_array_new (FALSE, TRUE, sizeof (CK_MECHANISM_TYPE));
 	for (i = 0; i < count; ++i)
@@ -753,7 +873,7 @@
 
 /**
  * gp11_slot_get_mechanism_info:
- * @slot: The slot to get mechanism info from.
+ * @self: The slot to get mechanism info from.
  * @mech_type: The mechanisms type to get info for.
  * 
  * Get information for the specified mechanism.
@@ -762,19 +882,29 @@
  * gp11_mechanism_info_free() when done with it.
  **/
 GP11MechanismInfo*
-gp11_slot_get_mechanism_info (GP11Slot *slot, gulong mech_type)
+gp11_slot_get_mechanism_info (GP11Slot *self, gulong mech_type)
 {
+	CK_SLOT_ID handle = (CK_SLOT_ID)-1;
+	CK_FUNCTION_LIST_PTR funcs;
 	GP11MechanismInfo *mechinfo;
+	GP11Module *module = NULL;
 	CK_MECHANISM_INFO info;
 	struct tm;
 	CK_RV rv;
 	
-	g_return_val_if_fail (GP11_IS_SLOT (slot), NULL);
-	g_return_val_if_fail (GP11_IS_MODULE (slot->module), NULL);
-	g_return_val_if_fail (slot->module->funcs, NULL);
+	g_return_val_if_fail (GP11_IS_SLOT (self), NULL);
+
+	g_object_get (self, "module", &module, "handle", &handle, NULL);
+	g_return_val_if_fail (GP11_IS_MODULE (module), NULL);
 	
+	funcs = gp11_module_get_function_list (module);
+	g_return_val_if_fail (funcs, NULL);
+		
 	memset (&info, 0, sizeof (info));
-	rv = (slot->module->funcs->C_GetMechanismInfo) (slot->handle, mech_type, &info);
+	rv = (funcs->C_GetMechanismInfo) (handle, mech_type, &info);
+	
+	g_object_unref (module);
+	
 	if (rv != CKR_OK) {
 		g_warning ("couldn't get mechanism info: %s", gp11_message_from_rv (rv));
 		return NULL;
@@ -806,20 +936,20 @@
 }
 
 gboolean
-gp11_slot_init_token (GP11Slot *slot, const guchar *pin, gsize length, 
+gp11_slot_init_token (GP11Slot *self, const guchar *pin, gsize length, 
                       const gchar *label, GCancellable *cancellable,
                       GError **err)
 {
 	InitToken args = { GP11_ARGUMENTS_INIT, pin, length, label };
-	return _gp11_call_sync (slot, perform_init_token, &args, err);
+	return _gp11_call_sync (self, perform_init_token, &args, err);
 }
 
 void
-gp11_slot_init_token_async (GP11Slot *slot, const guchar *pin, gsize length, 
+gp11_slot_init_token_async (GP11Slot *self, const guchar *pin, gsize length, 
                             const gchar *label, GCancellable *cancellable,
                             GAsyncReadyCallback callback, gpointer user_data)
 {
-	InitToken* args = _gp11_call_async_prep (slot, slot, perform_init_token, 
+	InitToken* args = _gp11_call_async_prep (self, self, perform_init_token, 
 	                                         sizeof (*args));
 	
 	args->pin = pin;
@@ -830,9 +960,9 @@
 }
 	
 gboolean
-gp11_slot_init_token_finish (GP11Slot *slot, GAsyncResult *result, GError **err)
+gp11_slot_init_token_finish (GP11Slot *self, GAsyncResult *result, GError **err)
 {
-	return _gp11_call_basic_finish (slot, result, err);
+	return _gp11_call_basic_finish (self, result, err);
 }
 
 #endif /* UNIMPLEMENTED */
@@ -853,7 +983,7 @@
 
 /**
  * gp11_slot_open_session:
- * @slot: The slot ot open a session on.
+ * @self: The slot ot open a session on.
  * @flags: The flags to open a session with.
  * @err: A location to return an error, or NULL.
  * 
@@ -865,14 +995,14 @@
  * Return value: A new session or NULL if an error occurs.
  **/
 GP11Session*
-gp11_slot_open_session (GP11Slot *slot, gulong flags, GError **err)
+gp11_slot_open_session (GP11Slot *self, gulong flags, GError **err)
 {
-	return gp11_slot_open_session_full (slot, flags, NULL, err);
+	return gp11_slot_open_session_full (self, flags, NULL, err);
 }
 
 /**
  * gp11_slot_open_session_full:
- * @slot: The slot to open a session on.
+ * @self: The slot to open a session on.
  * @flags: The flags to open a session with.
  * @cancellable: Optional cancellation object, or NULL.
  * @err: A location to return an error, or NULL.
@@ -885,26 +1015,42 @@
  * Return value: A new session or NULL if an error occurs.
  **/
 GP11Session*
-gp11_slot_open_session_full (GP11Slot *slot, gulong flags, GCancellable *cancellable, GError **err)
+gp11_slot_open_session_full (GP11Slot *self, gulong flags, GCancellable *cancellable, GError **err)
 {
-	OpenSession args = { GP11_ARGUMENTS_INIT, flags, 0 };
+	GP11SlotPrivate *pv;
+	GP11Session *session = NULL;
 	CK_SESSION_HANDLE handle;
+
+	flags |= CKF_SERIAL_SESSION;
+	
+	g_object_ref (self);
 	
-	/* Try to use a cached session */
-	handle = pop_session_table (slot, flags);
-	if (handle != 0)
-		return make_session_object (slot, flags, handle);
+	pv = lock_private (self);
 	
+	{
+		/* Try to use a cached session */
+		handle = pop_session_table (pv, flags);
+		if (handle != 0) 
+			session = make_session_object (self, flags, handle);
+	}
+
+	unlock_private (self, pv);
+
 	/* Open a new session */
-	if (!_gp11_call_sync (slot, perform_open_session, &args, cancellable, err))
-		return FALSE;
+	if (session == NULL) {
+		OpenSession args = { GP11_ARGUMENTS_INIT, flags, 0 };
+		if (_gp11_call_sync (self, perform_open_session, &args, cancellable, err))
+			session = make_session_object (self, flags, args.session);
+	}
+
+	g_object_unref (self);
 	
-	return make_session_object (slot, flags, args.session);
+	return session;
 }
 
 /**
  * gp11_slot_open_session_async:
- * @slot: The slot to open a session on.
+ * @self: The slot to open a session on.
  * @flags: The flags to open a session with.
  * @cancellable: Optional cancellation object, or NULL.
  * @callback: Called when the operation completes.
@@ -916,27 +1062,41 @@
  * This call will return immediately and complete asynchronously.
  **/
 void
-gp11_slot_open_session_async (GP11Slot *slot, gulong flags, GCancellable *cancellable, 
+gp11_slot_open_session_async (GP11Slot *self, gulong flags, GCancellable *cancellable, 
                               GAsyncReadyCallback callback, gpointer user_data)
 {
+	GP11SlotPrivate *pv;
 	GP11Call *call;
-	OpenSession *args = _gp11_call_async_prep (slot, slot, perform_open_session,
-	                                           sizeof (*args), NULL);
+	OpenSession *args;
+
+	flags |= CKF_SERIAL_SESSION;
+	
+	g_object_ref (self);
 	
-	/* Try to use a cached session */
-	args->session = pop_session_table (slot, flags);
-	args->flags = flags;
+	args =  _gp11_call_async_prep (self, self, perform_open_session, sizeof (*args), NULL);
+	
+	pv = lock_private (self);
+
+	{
+		/* Try to use a cached session */
+		args->session = pop_session_table (pv, flags);
+		args->flags = flags;
+	}
+	
+	unlock_private (self, pv);
 	
 	call = _gp11_call_async_ready (args, cancellable, callback, user_data);
 	if (args->session)
 		_gp11_call_async_short (call, CKR_OK);
 	else
 		_gp11_call_async_go (call);
+	
+	g_object_unref (self);
 }
 
 /**
  * gp11_slot_open_session_finish:
- * @slot: The slot to open a session on.
+ * @self: The slot to open a session on.
  * @result: The result passed to the callback.
  * @err: A location to return an error or NULL.
  * 
@@ -946,13 +1106,22 @@
  * Return value: The new session or NULL if an error occurs.
  */
 GP11Session*
-gp11_slot_open_session_finish (GP11Slot *slot, GAsyncResult *result, GError **err)
+gp11_slot_open_session_finish (GP11Slot *self, GAsyncResult *result, GError **err)
 {
-	OpenSession *args;
+	GP11Session *session = NULL;
+
+	g_object_ref (self);
 	
-	if (!_gp11_call_basic_finish (result, err))
-		return NULL;
+	{
+		OpenSession *args;
+
+		if (_gp11_call_basic_finish (result, err)) {
+			args = _gp11_call_arguments (result, OpenSession);
+			session = make_session_object (self, args->flags, args->session);
+		}
+	}
+	
+	g_object_unref (self);
 	
-	args = _gp11_call_arguments (result, OpenSession);
-	return make_session_object (slot, args->flags, args->session);
+	return session;
 }

Modified: trunk/gp11/gp11.h
==============================================================================
--- trunk/gp11/gp11.h	(original)
+++ trunk/gp11/gp11.h	Sat Dec 27 18:29:23 2008
@@ -243,25 +243,28 @@
 
 struct _GP11Module {
 	GObject parent;
-	
-	gchar *path;
-	CK_FUNCTION_LIST_PTR funcs;
+	gpointer reserved[4];
 };
 
 struct _GP11ModuleClass {
 	GObjectClass parent;
+	gpointer reserved[8];
 };
 
-GType               gp11_module_get_type                    (void) G_GNUC_CONST;
+GType                 gp11_module_get_type                    (void) G_GNUC_CONST;
 
-GP11Module*         gp11_module_initialize                  (const gchar *path, 
-                                                             gpointer reserved,
-                                                             GError **err);
+GP11Module*           gp11_module_initialize                  (const gchar *path, 
+                                                               gpointer reserved,
+                                                               GError **err);
+
+const gchar*          gp11_module_get_path                    (GP11Module *module);
+
+CK_FUNCTION_LIST_PTR  gp11_module_get_function_list           (GP11Module *module);
 
-GP11ModuleInfo*     gp11_module_get_info                    (GP11Module *module);
+GP11ModuleInfo*       gp11_module_get_info                    (GP11Module *module);
 
-GList*              gp11_module_get_slots                   (GP11Module *module,
-                                                             gboolean token_present);
+GList*                gp11_module_get_slots                   (GP11Module *module,
+                                                               gboolean token_present);
 
 enum {
 	GP11_IS_STRING = -1,
@@ -338,16 +341,14 @@
 
 struct _GP11Slot {
 	GObject parent;
-	
-	GP11Module *module;
-	CK_SLOT_ID handle;
+	gpointer reserved[4];
 };
 
 struct _GP11SlotClass {
 	GObjectClass parent;
 
 	gboolean (*authenticate_token) (GP11Slot *slot, gchar **password);
-	
+
 #ifdef UNIMPLEMENTED
 	gboolean (*authenticate_key) (GP11Slot *slot, GP11Object *object, 
 	                              gchar **password);
@@ -355,10 +356,13 @@
 	void (*slot_event) (GP11Slot *slot);
 #endif
 	
+	gpointer reserved[10];	
 };
 
 GType               gp11_slot_get_type                      (void) G_GNUC_CONST;
 
+GP11Module*         gp11_slot_get_module                    (GP11Slot *slot);
+
 CK_SLOT_ID          gp11_slot_get_handle                    (GP11Slot *slot);
 
 gboolean            gp11_slot_get_reuse_sessions            (GP11Slot *slot);
@@ -447,24 +451,26 @@
 
 struct _GP11Session {
 	GObject parent;
-	
-	GP11Slot *slot;
-	GP11Module *module;
-	CK_SESSION_HANDLE handle;	
 };
 
 struct _GP11SessionClass {
 	GObjectClass parent;
 
-	void (*discard_handle) (GP11Session *session);
+	gboolean (*discard_handle) (GP11Session *session, CK_SESSION_HANDLE handle);
 };
 
 GType               gp11_session_get_type                   (void) G_GNUC_CONST;
 
 GP11Session*        gp11_session_from_handle                (GP11Slot *slot, CK_SESSION_HANDLE handle); 
 
+GP11Module*         gp11_session_get_module                 (GP11Session *self);
+
+GP11Slot*           gp11_session_get_slot                   (GP11Session *self);
+
 CK_SESSION_HANDLE   gp11_session_get_handle                 (GP11Session *session);
 
+CK_SESSION_HANDLE   gp11_session_steal_handle               (GP11Session *session);
+
 GP11SessionInfo*    gp11_session_get_info                   (GP11Session *session);
 
 #if UNIMPLEMENTED
@@ -1195,11 +1201,6 @@
 
 struct _GP11Object {
 	GObject parent;
-	
-	GP11Module *module;
-	GP11Slot *slot;
-	GP11Session *session;
-	CK_OBJECT_HANDLE handle;
 };
 
 struct _GP11ObjectClass {
@@ -1214,6 +1215,10 @@
 GList*              gp11_objects_from_handle_array          (GP11Slot *slot,
                                                              const GP11Attribute *attr);
 
+GP11Module*         gp11_object_get_module                  (GP11Object *self);
+
+GP11Slot*           gp11_object_get_slot                    (GP11Object *object);
+
 CK_OBJECT_HANDLE    gp11_object_get_handle                  (GP11Object *object);
 
 GP11Session*        gp11_object_get_session                 (GP11Object *object);

Modified: trunk/gp11/tests/unit-test-gp11-module.c
==============================================================================
--- trunk/gp11/tests/unit-test-gp11-module.c	(original)
+++ trunk/gp11/tests/unit-test-gp11-module.c	Sat Dec 27 18:29:23 2008
@@ -40,7 +40,7 @@
 {
 	gchar *path;
 
-	g_object_get (module, "module-path", &path, NULL);
+	g_object_get (module, "path", &path, NULL);
 	g_assert (path != NULL && "no module-path");
 	g_assert (strcmp (".libs/libgp11-test-module.so", path) == 0 && "module path wrong");
 	g_free (path);

Modified: trunk/gp11/tests/unit-test-gp11-object.c
==============================================================================
--- trunk/gp11/tests/unit-test-gp11-object.c	(original)
+++ trunk/gp11/tests/unit-test-gp11-object.c	Sat Dec 27 18:29:23 2008
@@ -33,7 +33,7 @@
 	SUCCESS_RES(session, err);
 	
 	/* Our module always exports a token object with this */
-	object = gp11_object_from_handle (session->slot, 2);
+	object = gp11_object_from_handle (slot, 2);
 	g_assert (object != NULL);
 }
 
@@ -47,12 +47,12 @@
 
 DEFINE_TEST(object_props)
 {
-	GP11Slot *slot;
+	GP11Slot *sl;
 	GP11Module *mod;
 	CK_OBJECT_HANDLE handle;
-	g_object_get (object, "slot", &slot, "module", &mod, "handle", &handle, NULL);
-	g_assert (slot == session->slot);
-	g_object_unref (slot);
+	g_object_get (object, "slot", &sl, "module", &mod, "handle", &handle, NULL);
+	g_assert (slot == sl);
+	g_object_unref (sl);
 	g_assert (module == mod);
 	g_object_unref (mod);
 	g_assert (handle == 2);
@@ -84,7 +84,7 @@
 	g_assert (GP11_IS_OBJECT (object));
 	
 	if (object) {
-		last_handle = object->handle;
+		last_handle = gp11_object_get_handle (object);
 		g_object_unref (object);
 	}
 	
@@ -100,8 +100,8 @@
 	SUCCESS_RES (object, err);
 	
 	if (object) {
-		g_assert (last_handle != object->handle);
-		last_handle = object->handle;
+		g_assert (last_handle != gp11_object_get_handle (object));
+		last_handle = gp11_object_get_handle (object);
 		g_object_unref (object);
 	}
 
@@ -380,11 +380,13 @@
 
 	/* Set an explicit session */
 	gp11_object_set_session (object, session);
-	g_assert (gp11_object_get_session (object) == session);
+	sess = gp11_object_get_session (object);
+	g_assert (sess == session);
+	g_object_unref (sess);
 	g_object_get (object, "session", &sess, NULL);
 	g_assert (sess == session);
 	g_object_unref (sess);
-
+	
 	/* Simple */
 	attrs = gp11_object_get (object, &err, CKA_CLASS, CKA_LABEL, -1);
 	SUCCESS_RES (attrs, err);
@@ -415,4 +417,11 @@
 	g_assert (gp11_object_get_session (object) == NULL);
 	g_object_get (object, "session", &sess, NULL);
 	g_assert (sess == NULL);
+
+	/* Test property settor */
+	g_object_set (object, "session", session, NULL);
+	sess = gp11_object_get_session (object);
+	g_assert (sess == session);
+	gp11_object_set_session (object, NULL);
+	g_object_unref (sess);
 }

Modified: trunk/gp11/tests/unit-test-gp11-session.c
==============================================================================
--- trunk/gp11/tests/unit-test-gp11-session.c	(original)
+++ trunk/gp11/tests/unit-test-gp11-session.c	Sat Dec 27 18:29:23 2008
@@ -42,14 +42,17 @@
 DEFINE_TEST(session_props)
 {
 	GP11Module *mod;
+	GP11Slot *sl;
 	guint handle;
 	
-	g_object_get (session, "module", &mod, "handle", &handle, NULL);
+	g_object_get (session, "module", &mod, "handle", &handle, "slot", &sl, NULL);
 	g_assert (mod == module);
+	g_assert (sl == slot);
 	g_object_unref (mod);
+	g_object_unref (sl);
 	
 	g_assert (handle != 0);
-	g_assert (session->handle == handle);
+	g_assert (gp11_session_get_handle (session) == handle);
 }
 
 DEFINE_TEST(session_info)
@@ -59,7 +62,7 @@
 	info = gp11_session_get_info (session);
 	g_assert (info != NULL && "no session info");
 	
-	g_assert (info->slot_id == slot->handle); 
+	g_assert (info->slot_id == gp11_slot_get_handle (slot)); 
 	g_assert ((info->flags & CKF_SERIAL_SESSION) == CKF_SERIAL_SESSION); 
 	g_assert (info->device_error == 1414); 
 	gp11_session_info_free (info);
@@ -103,24 +106,27 @@
 	GP11Session *sess, *sess2;
 	GAsyncResult *result = NULL;
 	GError *err = NULL;
+	gboolean value;
 	
 	g_assert (gp11_slot_get_reuse_sessions (slot) == FALSE);
 	gp11_slot_set_reuse_sessions (slot, TRUE);
 	g_assert (gp11_slot_get_reuse_sessions (slot) == TRUE);
+	g_object_get (slot, "reuse-sessions", &value, NULL);
+	g_assert (value == TRUE);
 	
 	sess = gp11_slot_open_session (slot, 0, &err);
 	SUCCESS_RES (sess, err);
 	if (!sess) return;
 
 	/* Make note of the handle we saw */
-	handle = sess->handle;
+	handle = gp11_session_get_handle (sess);
 	g_object_unref (sess);
 	
 	/* Open again, and see if the same handle */
 	sess = gp11_slot_open_session (slot, 0, &err);
 	SUCCESS_RES (sess, err);
 	if (!sess) return;
-	g_assert (handle == sess->handle);
+	g_assert (handle == gp11_session_get_handle (sess));
 	g_object_unref (sess);
 	
 	/* Test opening async */
@@ -130,7 +136,7 @@
 	sess = gp11_slot_open_session_finish (slot, result, &err);
 	SUCCESS_RES (sess, err);
 	if (!sess) return;
-	g_assert (handle == sess->handle);
+	g_assert (handle == gp11_session_get_handle (sess));
 	g_object_unref (result);
 	g_object_unref (sess);
 	
@@ -138,14 +144,17 @@
 	sess = gp11_slot_open_session (slot, CKF_RW_SESSION, &err);
 	SUCCESS_RES (sess, err);
 	if (!sess) return;
-	g_assert (handle != sess->handle);
+	g_assert (handle != gp11_session_get_handle (sess));
 	
 	/* Now open a second session, with same flags, shouldn't return the same */
 	sess2 = gp11_slot_open_session (slot, CKF_RW_SESSION, &err);
 	SUCCESS_RES (sess2, err);
 	if (!sess2) return;
-	g_assert (sess->handle != sess2->handle);
+	g_assert (gp11_session_get_handle (sess) != gp11_session_get_handle (sess2));
 	
+	g_object_set (slot, "reuse-sessions", FALSE, NULL);
+	g_assert (gp11_slot_get_reuse_sessions (slot) == FALSE);
+
 	g_object_unref (sess);
 	g_object_unref (sess2);
 }
@@ -214,6 +223,7 @@
 	GError *err = NULL;
 	GP11Attributes *attrs;
 	gboolean ret;
+	gboolean value;
 	
 	attrs = gp11_attributes_newv (CKA_CLASS, GP11_ULONG, CKO_DATA,
 	                              CKA_LABEL, GP11_STRING, "TEST OBJECT",
@@ -230,6 +240,8 @@
 	g_assert (gp11_slot_get_auto_login (slot) == FALSE);
 	gp11_slot_set_auto_login (slot, TRUE);
 	g_assert (gp11_slot_get_auto_login (slot) == TRUE);
+	g_object_get (slot, "auto-login", &value, NULL);
+	g_assert (value == TRUE);
 	
 	g_signal_connect (slot, "authenticate-token", G_CALLBACK (authenticate_token), GUINT_TO_POINTER (35));
 
@@ -254,4 +266,7 @@
 	/* We should now be logged in, try to log out */
 	ret = gp11_session_logout (session, &err);
 	SUCCESS_RES (ret, err);
+	
+	g_object_set (slot, "auto-login", FALSE, NULL);
+	g_assert (gp11_slot_get_auto_login (slot) == FALSE);
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]