Add basic thread-safety.
authorStefan Walter <stefw@src.gnome.org>
Sat, 27 Dec 2008 18:29:23 +0000 (18:29 +0000)
committerStefan Walter <stefw@src.gnome.org>
Sat, 27 Dec 2008 18:29:23 +0000 (18:29 +0000)
* 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.

svn path=/trunk/; revision=1411

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/gp11.h
gp11/tests/unit-test-gp11-module.c
gp11/tests/unit-test-gp11-object.c
gp11/tests/unit-test-gp11-session.c

index c9c1ea6..0cf8bcd 100644 (file)
@@ -33,6 +33,7 @@ static gpointer _gp11_call_parent_class = NULL;
 
 struct _GP11Call {
        GObject parent;
+       GP11Module *module;
 
        /* For making the call */
        GP11CallFunc func;
@@ -131,6 +132,8 @@ process_async_call (gpointer data, GP11CallClass *klass)
 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 @@ process_result (GP11Call *call, gpointer unused)
        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 */
@@ -239,6 +244,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);
        call->object = NULL;
@@ -395,6 +404,7 @@ _gp11_call_sync (gpointer object, gpointer func, gpointer data,
        GP11Arguments *args = (GP11Arguments*)data;
        gchar *password = NULL;
        GP11Module *module = NULL;
+       GP11Slot *slot;
        CK_ULONG pin_len;
        CK_RV rv;
 
@@ -405,8 +415,9 @@ _gp11_call_sync (gpointer object, gpointer func, gpointer data,
        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,14 +428,15 @@ _gp11_call_sync (gpointer object, gpointer func, gpointer data,
        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 */
@@ -432,6 +444,8 @@ _gp11_call_sync (gpointer object, gpointer func, gpointer data,
                        rv = perform_call ((GP11CallFunc)func, cancellable, args);
        }
 
+       g_object_unref (module);
+
        if (rv == CKR_OK)
                return TRUE;
 
@@ -477,15 +491,18 @@ _gp11_call_async_prep (gpointer object, gpointer cb_object, gpointer func,
 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*
index 7e7cf5d..aaf14e7 100644 (file)
@@ -1,2 +1,3 @@
 BOOLEAN:POINTER
 BOOLEAN:OBJECT,POINTER
+BOOLEAN:ULONG
index 0d1c10e..1501757 100644 (file)
@@ -38,8 +38,13 @@ GQuark
 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;
 }
 
index b43c444..de5fa4a 100644 (file)
 
 #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 @@ unlock_mutex (void *mutex)
  */
 
 static void
-gp11_module_init (GP11Module *module)
+gp11_module_init (GP11Module *self)
 {
 
 }
@@ -103,11 +120,14 @@ static void
 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 @@ static void
 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 @@ gp11_module_set_property (GObject *obj, guint prop_id, const GValue *value,
 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 @@ gp11_module_class_init (GP11ModuleClass *klass)
        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 @@ GP11Module*
 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 @@ gp11_module_initialize (const gchar *path, gpointer reserved, GError **err)
        }
 
        /* 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 @@ gp11_module_initialize (const gchar *path, gpointer reserved, GError **err)
        }
 
        /* 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 @@ gp11_module_initialize (const gchar *path, gpointer reserved, GError **err)
                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_initialize (const gchar *path, gpointer reserved, GError **err)
 
 /**
  * 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_info (GP11Module *module)
 
 /**
  * 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 @@ gp11_module_get_info (GP11Module *module)
  * 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 @@ gp11_module_get_slots (GP11Module *module, gboolean token_present)
                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 @@ gp11_module_get_slots (GP11Module *module, gboolean token_present)
 
        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;
+}
index b7fb1a9..5230b6c 100644 (file)
 
 #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 @@ enum {
        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 @@ opened_session (GObject *obj, GAsyncResult *result, gpointer user_data)
 }
 
 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;
 
-       if (object->session)
-               return g_object_ref (object->session);
+       g_assert (GP11_IS_OBJECT (self));
 
-       return gp11_slot_open_session (object->slot, flags, err);
+       session = gp11_object_get_session (self);
+       if (session)
+               return session;
+
+       return gp11_slot_open_session (data->slot, flags, err);
 }
 
 /* ----------------------------------------------------------------------------
@@ -107,29 +139,30 @@ require_session_sync (GP11Object *object, gulong flags, GError **err)
  */
 
 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 @@ static void
 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);
-
-       if (object->slot)
-               g_object_unref (object->slot);
-       object->slot = NULL;
-
-       if (object->module)
-               g_object_unref (object->module);
-       object->module = NULL;
+       GP11ObjectPrivate *pv = (G_TYPE_INSTANCE_GET_PRIVATE(obj, GP11_TYPE_OBJECT, GP11ObjectPrivate));
+       GP11ObjectData *data = GP11_OBJECT_GET_DATA (obj);
 
-       if (object->session)
-               g_object_unref (object->session);
-       object->session = NULL;
+       if (data->slot)
+               g_object_unref (data->slot);
+       data->slot = NULL;
 
-       G_OBJECT_CLASS (gp11_object_parent_class)->dispose (obj);
-}
+       if (data->module)
+               g_object_unref (data->module);
+       data->module = NULL;
 
-static void
-gp11_object_finalize (GObject *obj)
-{
-       GP11Object *object = GP11_OBJECT (obj);
+       if (pv->session)
+               g_object_unref (pv->session);
+       pv->session = NULL;
 
-       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 @@ gp11_object_class_init (GP11ObjectClass *klass)
 
        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_object_class_init (GP11ObjectClass *klass)
                                     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 @@ gp11_object_class_init (GP11ObjectClass *klass)
 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_objects_from_handle_array (GP11Slot *slot, const GP11Attribute *attr)
 
 /**
  * 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 @@ gp11_object_get_handle (GP11Object *object)
  * 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 @@ gp11_object_get_session (GP11Object *object)
  * 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 @@ perform_destroy (Destroy *args)
 
 /**
  * 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 @@ perform_destroy (Destroy *args)
  * 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 @@ gp11_object_destroy (GP11Object *object, GError **err)
  * 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_full (GP11Object *object, GCancellable *cancellable, GError
 
 /**
  * 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 @@ gp11_object_destroy_full (GP11Object *object, GCancellable *cancellable, GError
  * 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 @@ gp11_object_destroy_async (GP11Object *object, GCancellable *cancellable,
  * 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 @@ perform_set_attributes (SetAttributes *args)
 
 /**
  * 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 @@ perform_set_attributes (SetAttributes *args)
  * 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 @@ gp11_object_set (GP11Object *object, GError **err, ...)
        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 (GP11Object *object, GError **err, ...)
 
 /**
  * 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 @@ gp11_object_set (GP11Object *object, GError **err, ...)
  * 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_full (GP11Object *object, GP11Attributes *attrs,
 
 /**
  * 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 @@ gp11_object_set_full (GP11Object *object, GP11Attributes *attrs,
  * 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 @@ gp11_object_set_async (GP11Object *object, GP11Attributes *attrs, GCancellable *
  * 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 @@ perform_get_attributes (GetAttributes *args)
 
 /**
  * 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 @@ perform_get_attributes (GetAttributes *args)
  * 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 @@ gp11_object_get (GP11Object *object, GError **err, ...)
        }
        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 @@ gp11_object_get (GP11Object *object, GError **err, ...)
  * 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_full (GP11Object *object, const gulong *attr_types, gsize n_attr
 
 /**
  * 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 @@ gp11_object_get_full (GP11Object *object, const gulong *attr_types, gsize n_attr
  * 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 @@ gp11_object_get_async (GP11Object *object, const gulong *attr_types, gsize n_att
  * 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_finish (GP11Object *object, GAsyncResult *result, GError **err)
 
 /**
  * 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 @@ gp11_object_get_finish (GP11Object *object, GAsyncResult *result, GError **err)
  * 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 @@ gp11_object_get_one (GP11Object *object, gulong attr_type, GError **err)
  * 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_full (GP11Object *object, gulong attr_type,
 
 /**
  * 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 @@ gp11_object_get_one_full (GP11Object *object, gulong attr_type,
  * 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 @@ gp11_object_get_one_async (GP11Object *object, gulong attr_type, GCancellable *c
  **/
 
 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;
 
index 10495d6..6c7a758 100644 (file)
@@ -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 @@ enum {
        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,8 +64,33 @@ static guint signals[LAST_SIGNAL] = { 0 };
  * OBJECT
  */
 
+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 *session)
+gp11_session_init (GP11Session *self)
 {
 
 }
@@ -58,41 +99,43 @@ 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,35 +143,25 @@ gp11_session_set_property (GObject *obj, guint prop_id, const GValue *value,
 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;
+       discarded = g_atomic_int_get (&data->discarded);
+       if (!discarded && g_atomic_int_compare_and_exchange (&data->discarded, discarded, 1)) {
 
-       if (session->module)
-               g_object_unref (session->module);
-       session->module = NULL;
+               /*
+                * 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);
 }
@@ -136,15 +169,21 @@ gp11_session_dispose (GObject *obj)
 static void
 gp11_session_finalize (GObject *obj)
 {
-       GP11Session *session = GP11_SESSION (obj);
+       GP11SessionData *data = GP11_SESSION_GET_DATA (obj);
+
+       g_assert (data->discarded != 0);
 
-       g_assert (session->module == NULL);
-       g_assert (session->handle == 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 @@ gp11_session_class_init (GP11SessionClass *klass)
        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 @@ gp11_session_info_free (GP11SessionInfo *session_info)
 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 @@ gp11_session_get_handle (GP11Session *session)
  * 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 @@ perform_login (Login *args)
 
 /**
  * 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 @@ perform_login (Login *args)
  * 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 @@ gp11_session_login (GP11Session *session, gulong user_type, const guchar *pin,
  * 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 @@ gp11_session_login_full (GP11Session *session, gulong user_type, const guchar *p
  * 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_async (GP11Session *session, gulong user_type, const guchar *
 
 /**
  * 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 @@ gp11_session_login_async (GP11Session *session, gulong user_type, const guchar *
  * 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 @@ perform_logout (GP11Arguments *args)
 
 /**
  * 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 @@ perform_logout (GP11Arguments *args)
  * 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 @@ gp11_session_logout (GP11Session *session, GError **err)
  * 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 @@ gp11_session_logout_full (GP11Session *session, GCancellable *cancellable, GErro
  * 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 @@ gp11_session_logout_async (GP11Session *session, GCancellable *cancellable,
  * 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 @@ perform_create_object (CreateObject *args)
 
 /**
  * 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 @@ perform_create_object (CreateObject *args)
  * 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 @@ gp11_session_create_object (GP11Session *session, GError **err, ...)
        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 @@ gp11_session_create_object (GP11Session *session, GError **err, ...)
  * 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 @@ gp11_session_create_object_full (GP11Session *session, GP11Attributes *attrs,
  * 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_async (GP11Session *session, GP11Attributes *attrs,
 
 /**
  * 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 @@ gp11_session_create_object_async (GP11Session *session, GP11Attributes *attrs,
  * 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 @@ perform_find_objects (FindObjects *args)
 }
 
 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 @@ objlist_from_handles (GP11Session *session, CK_OBJECT_HANDLE_PTR objects,
 
 /**
  * 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 @@ objlist_from_handles (GP11Session *session, CK_OBJECT_HANDLE_PTR objects,
  * 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 @@ gp11_session_find_objects (GP11Session *session, GError **err, ...)
        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 @@ gp11_session_find_objects (GP11Session *session, GError **err, ...)
  * 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 @@ gp11_session_find_objects_full (GP11Session *session, GP11Attributes *attrs,
  * 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_async (GP11Session *session, GP11Attributes *attrs,
 
 /**
  * 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 @@ gp11_session_find_objects_async (GP11Session *session, GP11Attributes *attrs,
  * 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 @@ perform_crypt (Crypt *args)
 }
 
 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 @@ crypt_sync (GP11Session *session, GP11Object *key, GP11Mechanism *mech_args, con
        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 @@ crypt_sync (GP11Session *session, GP11Object *key, GP11Mechanism *mech_args, con
 }
 
 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 @@ crypt_async (GP11Session *session, GP11Object *key, GP11Mechanism *mech_args, co
 }
 
 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 @@ crypt_finish (GP11Session *session, GAsyncResult *result, gsize *n_result, GErro
 }
 
 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 @@ gp11_session_encrypt_full (GP11Session *session, GP11Object *key, GP11Mechanism
 }
 
 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 @@ perform_verify (Verify *args)
 }
 
 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 @@ gp11_session_verify_full (GP11Session *session, GP11Object *key, GP11Mechanism *
        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 @@ gp11_session_verify_async (GP11Session *session, GP11Object *key, GP11Mechanism
 }
 
 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 */
index cb50c05..5072abe 100644 (file)
@@ -46,7 +46,14 @@ enum {
        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 @@ typedef struct _GP11SlotPrivate {
 
 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,211 +109,215 @@ timegm(struct tm *t)
  * 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);
 
-#ifdef UNUSED
+       g_object_ref (self);
 
-static void
-foreach_count_sessions (gpointer key, gpointer value, gpointer user_data)
-{
-       SessionPool *pool = value;
-       guint *result = user_data;
-       *result += pool->sessions->len;
+       pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GP11_TYPE_SLOT, GP11SlotPrivate);
+       g_static_mutex_lock (&pv->mutex);
+
+       return pv;
 }
 
-static guint
-count_session_table (GP11Slot *slot, guint flags)
+static void
+unlock_private (gpointer obj, GP11SlotPrivate *pv)
 {
-       GP11SlotPrivate *pv = GP11_SLOT_GET_PRIVATE (slot);
-       guint result = 0;
+       GP11Slot *self;
 
-       if (!pv->open_sessions)
-               return 0;
+       g_assert (pv);
+       g_assert (GP11_IS_SLOT (obj));
 
-       g_hash_table_foreach (pv->open_sessions, foreach_count_sessions, &result);
-       return result;
-}
+       self = GP11_SLOT (obj);
+
+       g_assert (G_TYPE_INSTANCE_GET_PRIVATE (self, GP11_TYPE_SLOT, GP11SlotPrivate) == pv);
 
-#endif /* UNUSED */
+       g_static_mutex_unlock (&pv->mutex);
+       g_object_unref (self);
+}
 
 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;
+       SessionPool *pool = p;
+       guint i;
 
-       if (!pv->open_sessions) {
-               close_session (slot->module, handle);
-               return;
-       }
+       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_return_val_if_fail (pv, 0);
 
-       g_assert (GP11_IS_MODULE (slot->module));
 
-       pool = g_hash_table_lookup (pv->open_sessions, &flags);
-       if (!pool)
-               return 0;
+       g_assert (GP11_IS_MODULE (pv->data.module));
 
-       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);
+       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);
+       rv = (funcs->C_GetSessionInfo) (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;
-       }
+       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);
 
-       /*
-        * 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;
+               {
+                       handled = push_session_table (pv, info.flags, handle);
+               }
+
+               unlock_private (self, pv);
+
+       } 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);
+       g_object_ref (self);
 
-       /* 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);
+               session = gp11_session_from_handle (self, handle);
+               g_return_val_if_fail (session != NULL, NULL);
 
-       return session;
-}
+               /* Session keeps a reference to us, so this is safe */
+               g_signal_connect (session, "discard-handle", G_CALLBACK (reuse_session_handle), self);
 
-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);
+       g_object_unref (self);
+
+       return session;
 }
 
 /* ----------------------------------------------------------------------------
@@ -314,30 +325,30 @@ ensure_token_info (GP11Slot *slot)
  */
 
 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 @@ static void
 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 @@ gp11_slot_set_property (GObject *obj, guint prop_id, const GValue *value,
 static void
 gp11_slot_dispose (GObject *obj)
 {
-       GP11Slot *slot = GP11_SLOT (obj);
+       GP11SlotPrivate *pv = lock_private (obj);
 
-       /* Need to do this before the module goes away */
-       destroy_session_table (slot);
+       {
+               /* 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 @@ gp11_slot_dispose (GObject *obj)
 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);
 
-       g_assert (slot->module == NULL);
-       slot->handle = 0;
+       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_static_mutex_free (&pv->mutex);
 
        G_OBJECT_CLASS (gp11_slot_parent_class)->finalize (obj);
 }
@@ -415,8 +437,8 @@ gp11_slot_class_init (GP11SlotClass *klass)
                                     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 @@ gp11_slot_class_init (GP11SlotClass *klass)
  */
 
 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_mechanism_info_free (GP11MechanismInfo *mech_info)
 
 /**
  * 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 @@ gp11_slot_get_handle (GP11Slot *slot)
  * 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 @@ gp11_slot_set_reuse_sessions (GP11Slot *slot, gboolean reuse)
  * 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 @@ gp11_slot_get_auto_login (GP11Slot *slot)
  * 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 @@ gp11_slot_set_auto_login (GP11Slot *slot, gboolean auto_login)
  * 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_info (GP11Slot *slot)
 
 /**
  * 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 @@ gp11_slot_get_info (GP11Slot *slot)
  * 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_token_info (GP11Slot *slot)
 
 /**
  * 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_slot_get_token_info (GP11Slot *slot)
  * 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);
+
+       g_object_get (self, "module", &module, "handle", &handle, NULL);
+       g_return_val_if_fail (GP11_IS_MODULE (module), NULL);
 
-       rv = (slot->module->funcs->C_GetMechanismList) (slot->handle, NULL, &count);
+       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_mechanisms (GP11Slot *slot)
 
 /**
  * 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_slot_get_mechanisms (GP11Slot *slot)
  * 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 @@ perform_init_token (InitToken *args)
 }
 
 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 @@ gp11_slot_init_token_async (GP11Slot *slot, const guchar *pin, gsize length,
 }
 
 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 @@ perform_open_session (OpenSession *args)
 
 /**
  * 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 @@ perform_open_session (OpenSession *args)
  * 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 @@ gp11_slot_open_session (GP11Slot *slot, gulong flags, GError **err)
  * 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;
 
-       /* Try to use a cached session */
-       handle = pop_session_table (slot, flags);
-       if (handle != 0)
-               return make_session_object (slot, flags, handle);
+       flags |= CKF_SERIAL_SESSION;
+
+       g_object_ref (self);
+
+       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 @@ gp11_slot_open_session_full (GP11Slot *slot, gulong flags, GCancellable *cancell
  * 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);
+
+       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 (slot, flags);
-       args->flags = flags;
+       {
+               /* 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 @@ gp11_slot_open_session_async (GP11Slot *slot, gulong flags, GCancellable *cancel
  * 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;
 
-       if (!_gp11_call_basic_finish (result, err))
-               return NULL;
+       g_object_ref (self);
 
-       args = _gp11_call_arguments (result, OpenSession);
-       return make_session_object (slot, args->flags, args->session);
+       {
+               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);
+
+       return session;
 }
index 50bf817..097274c 100644 (file)
@@ -243,25 +243,28 @@ typedef struct _GP11ModuleClass GP11ModuleClass;
 
 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,9 +341,7 @@ typedef struct _GP11SlotClass GP11SlotClass;
 
 struct _GP11Slot {
        GObject parent;
-
-       GP11Module *module;
-       CK_SLOT_ID handle;
+       gpointer reserved[4];
 };
 
 struct _GP11SlotClass {
@@ -355,10 +356,13 @@ struct _GP11SlotClass {
        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 @@ typedef struct _GP11SessionClass GP11SessionClass;
 
 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 @@ typedef struct _GP11ObjectClass GP11ObjectClass;
 
 struct _GP11Object {
        GObject parent;
-
-       GP11Module *module;
-       GP11Slot *slot;
-       GP11Session *session;
-       CK_OBJECT_HANDLE handle;
 };
 
 struct _GP11ObjectClass {
@@ -1214,6 +1215,10 @@ GP11Object*         gp11_object_from_handle                 (GP11Slot *slot,
 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);
index c0dc4c0..e5f1d1c 100644 (file)
@@ -40,7 +40,7 @@ DEFINE_TEST(module_props)
 {
        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);
index 31e9c6e..9445633 100644 (file)
@@ -33,7 +33,7 @@ DEFINE_SETUP(prep_object)
        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_TEARDOWN(prep_object)
 
 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 @@ DEFINE_TEST(create_object)
        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 @@ DEFINE_TEST(create_object)
        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,7 +380,9 @@ DEFINE_TEST(explicit_sessions)
 
        /* 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);
@@ -415,4 +417,11 @@ DEFINE_TEST(explicit_sessions)
        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);
 }
index 1274b76..ed6e189 100644 (file)
@@ -42,14 +42,17 @@ DEFINE_TEARDOWN(load_session)
 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 @@ DEFINE_TEST(session_info)
        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 @@ DEFINE_TEST(open_reused)
        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 @@ DEFINE_TEST(open_reused)
        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,13 +144,16 @@ DEFINE_TEST(open_reused)
        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 @@ DEFINE_TEST(auto_login)
        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 @@ DEFINE_TEST(auto_login)
        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 @@ DEFINE_TEST(auto_login)
        /* 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);
 }