diff options
author | Stef Walter <stefw@collabora.co.uk> | 2011-11-02 14:10:43 +0100 |
---|---|---|
committer | Stef Walter <stefw@collabora.co.uk> | 2011-11-02 14:10:43 +0100 |
commit | 468414442f0c4a785fcf784752cae8a1e44323c9 (patch) | |
tree | 17a19b29060f1a0b22d55020583ded479a56bda7 | |
parent | 83c859210e66ffa5e0d7814cb822066c23c1e7bb (diff) | |
download | gcr-468414442f0c4a785fcf784752cae8a1e44323c9.tar.gz |
gck: Chaining of enumerators
* Add functions gck_enumerator_get_chained() and
gck_enumerator_set_chained()
* Chaining enumerator returns results from the chained enumerator
after all results have been retrieved from the former.
-rw-r--r-- | docs/reference/gck/gck-sections.txt | 2 | ||||
-rw-r--r-- | gck/gck-enumerator.c | 198 | ||||
-rw-r--r-- | gck/gck.h | 5 | ||||
-rw-r--r-- | gck/gck.symbols | 2 | ||||
-rw-r--r-- | gck/tests/test-gck-enumerator.c | 40 |
5 files changed, 210 insertions, 37 deletions
diff --git a/docs/reference/gck/gck-sections.txt b/docs/reference/gck/gck-sections.txt index 5a36a28..da8cab5 100644 --- a/docs/reference/gck/gck-sections.txt +++ b/docs/reference/gck/gck-sections.txt @@ -358,6 +358,8 @@ gck_enumerator_get_interaction gck_enumerator_set_interaction gck_enumerator_get_object_type gck_enumerator_set_object_type +gck_enumerator_get_chained +gck_enumerator_set_chained <SUBSECTION Standard> GckEnumeratorClass gck_enumerator_get_type diff --git a/gck/gck-enumerator.c b/gck/gck-enumerator.c index 060b355..933c344 100644 --- a/gck/gck-enumerator.c +++ b/gck/gck-enumerator.c @@ -46,7 +46,8 @@ enum { PROP_0, PROP_INTERACTION, - PROP_OBJECT_TYPE + PROP_OBJECT_TYPE, + PROP_CHAINED }; /** @@ -67,6 +68,9 @@ typedef gpointer (*GckEnumeratorFunc) (GckEnumeratorState *args, gboolean forward); struct _GckEnumeratorState { + gpointer enumerator; + GckEnumeratorState *chained; + /* For the current call */ gint want_objects; @@ -105,6 +109,7 @@ struct _GckEnumeratorPrivate { GTlsInteraction *interaction; GType object_type; GckObjectClass *object_class; + GckEnumerator *chained; }; G_DEFINE_TYPE (GckEnumerator, gck_enumerator, G_TYPE_OBJECT); @@ -492,8 +497,6 @@ state_attributes (GckEnumeratorState *args, session = gck_session_get_handle (args->session); g_return_val_if_fail (session, NULL); - count = 0; - /* Get the attributes for want_objects */ for (count = 0, l = args->results->head; l != NULL && count < args->want_objects; @@ -545,19 +548,22 @@ state_results (GckEnumeratorState *args, gboolean forward) { g_assert (args->results != NULL); + gint length; /* No cleanup, just unwind */ if (!forward) return state_authenticated; - while (args->want_objects > g_queue_get_length (args->results)) { + length = g_queue_get_length (args->results); + + while (args->want_objects > length) { _gck_debug ("wanted %d objects, have %d, looking for more", - args->want_objects, g_queue_get_length (args->results)); + args->want_objects, length); return rewind_state (args, state_slots); } _gck_debug ("wanted %d objects, returned %d objects", - args->want_objects, g_queue_get_length (args->results)); + args->want_objects, length); /* We got all the results we wanted */ return NULL; @@ -589,6 +595,9 @@ gck_enumerator_get_property (GObject *obj, case PROP_OBJECT_TYPE: g_value_set_gtype (value, gck_enumerator_get_object_type (self)); break; + case PROP_CHAINED: + g_value_set_object (value, gck_enumerator_get_chained (self)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; @@ -610,6 +619,9 @@ gck_enumerator_set_property (GObject *obj, case PROP_OBJECT_TYPE: gck_enumerator_set_object_type (self, g_value_get_gtype (value)); break; + case PROP_CHAINED: + gck_enumerator_set_chained (self, g_value_get_object (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; @@ -622,6 +634,7 @@ gck_enumerator_dispose (GObject *obj) GckEnumerator *self = GCK_ENUMERATOR (obj); gck_enumerator_set_interaction (self, NULL); + gck_enumerator_set_chained (self, NULL); G_OBJECT_CLASS (gck_enumerator_parent_class)->dispose (obj); } @@ -675,6 +688,16 @@ gck_enumerator_class_init (GckEnumeratorClass *klass) g_object_class_install_property (gobject_class, PROP_OBJECT_TYPE, g_param_spec_gtype ("object-type", "Object Type", "Type of objects created", GCK_TYPE_OBJECT, G_PARAM_READWRITE)); + + /** + * GckEnumerator:chained: + * + * Chained enumerator, which will be enumerated when this enumerator + * has enumerated all its objects. + */ + g_object_class_install_property (gobject_class, PROP_CHAINED, + g_param_spec_object ("chained", "Chained", "Chained enumerator", + GCK_TYPE_ENUMERATOR, G_PARAM_READWRITE)); } static void @@ -775,6 +798,7 @@ _gck_enumerator_new_for_session (GckSession *session, typedef struct _EnumerateNext { GckArguments base; GckEnumeratorState *state; + gint want_objects; } EnumerateNext; static CK_RV @@ -782,17 +806,23 @@ perform_enumerate_next (EnumerateNext *args) { GckEnumeratorFunc handler; GckEnumeratorState *state; + gint count = 0; g_assert (args->state); - state = args->state; - g_assert (state->handler); + for (state = args->state; state != NULL; state = state->chained) { + g_assert (state->handler); + state->want_objects = args->want_objects - count; + for (;;) { + handler = (state->handler) (state, TRUE); + if (!handler) + break; + state->handler = handler; + } - for (;;) { - handler = (state->handler) (state, TRUE); - if (!handler) + count += state->results ? g_queue_get_length (state->results) : 0; + if (count >= args->want_objects) break; - state->handler = handler; } /* TODO: In some modes, errors */ @@ -872,6 +902,64 @@ gck_enumerator_set_object_type (GckEnumerator *self, } /** + * gck_enumerator_get_chained: + * @self: the enumerator + * + * Get the enumerator that will be run after all objects from this one + * are seen. + * + * Returns: (transfer full) (allow-none): the chained enumerator or %NULL + */ +GckEnumerator * +gck_enumerator_get_chained (GckEnumerator *self) +{ + GckEnumerator *chained = NULL; + + g_return_val_if_fail (GCK_IS_ENUMERATOR (self), NULL); + + g_mutex_lock (self->pv->mutex); + + if (self->pv->chained) + chained = g_object_ref (self->pv->chained); + + g_mutex_unlock (self->pv->mutex); + + return chained; +} + +/** + * gck_enumerator_set_interaction: + * @self: the enumerator + * @chained: (allow-none): the chained enumerator or %NULL + * + * Set a chained enumerator that will be run after all objects from this one + * are seen. + */ +void +gck_enumerator_set_chained (GckEnumerator *self, + GckEnumerator *chained) +{ + GckEnumerator *old_chained = NULL; + + g_return_if_fail (GCK_IS_ENUMERATOR (self)); + g_return_if_fail (chained == NULL || GCK_IS_ENUMERATOR (chained)); + + g_mutex_lock (self->pv->mutex); + + old_chained = self->pv->chained; + if (chained) + g_object_ref (chained); + self->pv->chained = chained; + + g_mutex_unlock (self->pv->mutex); + + if (old_chained) + g_object_unref (old_chained); + + g_object_notify (G_OBJECT (self), "chained"); +} + +/** * gck_enumerator_get_interaction: * @self: the enumerator * @@ -931,6 +1019,16 @@ static GckEnumeratorState * check_out_enumerator_state (GckEnumerator *self) { GckEnumeratorState *state = NULL; + GTlsInteraction *old_interaction = NULL; + gpointer old_object_class = NULL; + GckEnumeratorState *chained_state = NULL; + GckEnumerator *chained; + + chained = gck_enumerator_get_chained (self); + if (chained) { + chained_state = check_out_enumerator_state (chained); + g_object_unref (chained); + } g_mutex_lock (self->pv->mutex); @@ -938,12 +1036,17 @@ check_out_enumerator_state (GckEnumerator *self) state = self->pv->the_state; self->pv->the_state = NULL; - g_clear_object (&state->interaction); + state->enumerator = g_object_ref (self); + g_assert (state->chained == NULL); + state->chained = chained_state; + + old_interaction = state->interaction; if (self->pv->interaction) state->interaction = g_object_ref (self->pv->interaction); + else + state->interaction = NULL; - if (state->object_class) - g_type_class_unref (state->object_class); + old_object_class = state->object_class; /* Must already be holding a reference, state also holds a ref */ state->object_type = self->pv->object_type; @@ -959,36 +1062,57 @@ check_out_enumerator_state (GckEnumerator *self) if (state == NULL) g_warning ("this enumerator is already running a next operation"); + /* Free these outside the lock */ + if (old_interaction) + g_object_unref (old_interaction); + if (old_object_class) + g_type_class_unref (old_object_class); + return state; } static void -check_in_enumerator_state (GckEnumerator *self, - GckEnumeratorState *state) +check_in_enumerator_state (GckEnumeratorState *state) { + GckEnumeratorState *chained = NULL; + GckEnumerator *self; + + g_assert (GCK_IS_ENUMERATOR (state->enumerator)); + self = state->enumerator; + g_mutex_lock (self->pv->mutex); + state->enumerator = NULL; g_assert (self->pv->the_state == NULL); self->pv->the_state = state; + chained = state->chained; + state->chained = NULL; g_mutex_unlock (self->pv->mutex); + + /* matches ref in check_in */ + g_object_unref (self); + + if (chained) + check_in_enumerator_state (chained); } static GckObject * extract_result (GckEnumeratorState *state) { - GckEnumeratorResult *result; + GckEnumeratorResult *result = NULL; GckModule *module; GckObject *object; g_assert (state != NULL); - if (state->results == NULL) - return NULL; - - result = g_queue_pop_head (state->results); - if (result == NULL) + if (state->results != NULL) + result = g_queue_pop_head (state->results); + if (result == NULL) { + if (state->chained) + return extract_result (state->chained); return NULL; + } module = gck_session_get_module (result->session); object = g_object_new (state->object_type, @@ -1044,7 +1168,7 @@ gck_enumerator_next (GckEnumerator *self, GCancellable *cancellable, GError **error) { - EnumerateNext args = { GCK_ARGUMENTS_INIT, NULL, }; + EnumerateNext args = { GCK_ARGUMENTS_INIT, NULL, 0, }; GckObject *result = NULL; g_return_val_if_fail (GCK_IS_ENUMERATOR (self), NULL); @@ -1056,17 +1180,17 @@ gck_enumerator_next (GckEnumerator *self, /* A result from a previous run? */ result = extract_result (args.state); if (result == NULL) { - args.state->want_objects = 1; + args.want_objects = 1; /* Run the operation and steal away the results */ if (_gck_call_sync (NULL, perform_enumerate_next, NULL, &args, cancellable, error)) result = extract_result (args.state); - args.state->want_objects = 0; + args.want_objects = 0; } /* Put the state back */ - check_in_enumerator_state (self, args.state); + check_in_enumerator_state (args.state); return result; } @@ -1094,7 +1218,7 @@ gck_enumerator_next_n (GckEnumerator *self, GCancellable *cancellable, GError **error) { - EnumerateNext args = { GCK_ARGUMENTS_INIT, NULL, }; + EnumerateNext args = { GCK_ARGUMENTS_INIT, NULL, 0, }; GList *results = NULL; gint want_objects; @@ -1111,21 +1235,21 @@ gck_enumerator_next_n (GckEnumerator *self, /* A result from a previous run? */ results = extract_results (args.state, &want_objects); if (want_objects > 0) { - args.state->want_objects = want_objects; + args.want_objects = want_objects; /* Run the operation and steal away the results */ if (_gck_call_sync (NULL, perform_enumerate_next, NULL, &args, cancellable, error)) results = g_list_concat (results, extract_results (args.state, &want_objects)); - args.state->want_objects = 0; + args.want_objects = 0; } + /* Put the state back */ + check_in_enumerator_state (args.state); + if (results) g_clear_error (error); - /* Put the state back */ - check_in_enumerator_state (self, args.state); - return results; } @@ -1158,9 +1282,9 @@ gck_enumerator_next_async (GckEnumerator *self, gint max_objects, GCancellable * state = check_out_enumerator_state (self); g_return_if_fail (state != NULL); - state->want_objects = max_objects <= 0 ? G_MAXINT : max_objects; args = _gck_call_async_prep (NULL, self, perform_enumerate_next, NULL, sizeof (*args), free_enumerate_next); + args->want_objects = max_objects <= 0 ? G_MAXINT : max_objects; args->state = state; _gck_call_async_ready_go (args, cancellable, callback, user_data); @@ -1194,14 +1318,14 @@ gck_enumerator_next_finish (GckEnumerator *self, GAsyncResult *result, GError ** args = _gck_call_arguments (result, EnumerateNext); state = args->state; args->state = NULL; - want_objects = state->want_objects; - state->want_objects = 0; + want_objects = args->want_objects; + args->want_objects = 0; if (_gck_call_basic_finish (result, error)) results = extract_results (state, &want_objects); /* Put the state back */ - check_in_enumerator_state (self, state); + check_in_enumerator_state (state); g_object_unref (self); @@ -461,6 +461,11 @@ GType gck_enumerator_get_object_type (GckEnumerator *se void gck_enumerator_set_object_type (GckEnumerator *self, GType object_type); +GckEnumerator * gck_enumerator_get_chained (GckEnumerator *self); + +void gck_enumerator_set_chained (GckEnumerator *self, + GckEnumerator *chained); + GckObject * gck_enumerator_next (GckEnumerator *self, GCancellable *cancellable, GError **error); diff --git a/gck/gck.symbols b/gck/gck.symbols index 5070913..f336260 100644 --- a/gck/gck.symbols +++ b/gck/gck.symbols @@ -57,6 +57,7 @@ gck_attributes_set_date gck_attributes_set_string gck_attributes_set_ulong gck_attributes_unref +gck_enumerator_get_chained gck_enumerator_get_interaction gck_enumerator_get_object_type gck_enumerator_get_type @@ -64,6 +65,7 @@ gck_enumerator_next gck_enumerator_next_async gck_enumerator_next_finish gck_enumerator_next_n +gck_enumerator_set_chained gck_enumerator_set_interaction gck_enumerator_set_object_type gck_error_get_quark diff --git a/gck/tests/test-gck-enumerator.c b/gck/tests/test-gck-enumerator.c index d46d437..b248b4e 100644 --- a/gck/tests/test-gck-enumerator.c +++ b/gck/tests/test-gck-enumerator.c @@ -499,6 +499,45 @@ test_attribute_get (Test *test, g_object_unref (en); } +static void +test_chained (Test *test, + gconstpointer unused) +{ + GckEnumerator *one; + GckEnumerator *two; + GckEnumerator *three; + GckUriData *uri_data; + GError *error = NULL; + GList *objects; + + uri_data = gck_uri_data_new (); + uri_data->attributes = gck_attributes_new (); + gck_attributes_add_ulong (uri_data->attributes, CKA_CLASS, CKO_PUBLIC_KEY); + one = _gck_enumerator_new_for_modules (test->modules, 0, uri_data); + + uri_data = gck_uri_data_new (); + uri_data->attributes = gck_attributes_new (); + gck_attributes_add_ulong (uri_data->attributes, CKA_CLASS, CKO_PRIVATE_KEY); + two = _gck_enumerator_new_for_modules (test->modules, 0, uri_data); + gck_enumerator_set_chained (one, two); + + uri_data = gck_uri_data_new (); + uri_data->attributes = gck_attributes_new (); + gck_attributes_add_ulong (uri_data->attributes, CKA_CLASS, CKO_DATA); + three = _gck_enumerator_new_for_modules (test->modules, 0, uri_data); + gck_enumerator_set_chained (two, three); + + g_object_unref (two); + g_object_unref (three); + + objects = gck_enumerator_next_n (one, -1, NULL, &error); + g_assert_no_error (error); + g_assert_cmpint (g_list_length (objects), ==, 5); + + gck_list_unref_free (objects); + g_object_unref (one); +} + int main (int argc, char **argv) { @@ -520,6 +559,7 @@ main (int argc, char **argv) g_test_add ("/gck/enumerator/attribute_match", Test, NULL, setup, test_attribute_match, teardown); g_test_add ("/gck/enumerator/token_match", Test, NULL, setup, test_token_match, teardown); g_test_add ("/gck/enumerator/attribute_get", Test, NULL, setup, test_attribute_get, teardown); + g_test_add ("/gck/enumerator/chained", Test, NULL, setup, test_chained, teardown); return egg_tests_run_in_thread_with_loop (); } |