-lockmanager acquire retry
[oweals/gnunet.git] / src / lockmanager / gnunet-service-lockmanager.c
index b4abf6b8864a185bbd21e653181ca65ce9b97b8b..b5126ba20e748417b6a7aa1c59f52f5df11ec27d 100644 (file)
@@ -158,6 +158,28 @@ struct ClientList
 };
 
 
+/**
+ * Structure for matching a lock
+ */
+struct LockMatch
+{
+  /**
+   * The matched LockingRequest entry; Should be NULL if no entry is found
+   */
+  struct Lock *matched_entry;
+
+  /**
+   * The locking domain name of the lock
+   */
+  const char *domain_name;
+
+  /**
+   * The lock number
+   */
+  uint32_t lock_num;
+};
+
+
 /**
  * Map of lock-keys to the 'struct LockList' entry for the key.
  */
@@ -181,7 +203,7 @@ static struct ClientList *cl_tail;
  * @param lock_number
  * @param key set to the key
  */
-static inline void
+static void
 get_key (const char *domain_name,
         uint32_t lock_number,
         struct GNUNET_HashCode *key)
@@ -196,6 +218,32 @@ get_key (const char *domain_name,
 }
 
 
+/**
+ * Hashmap iterator for matching a lock
+ *
+ * @param cls the LockMatch structure
+ * @param key current key code
+ * @param value value in the hash map (struct Lock)
+ * @return GNUNET_YES if we should continue to
+ *         iterate,
+ *         GNUNET_NO if not. 
+ */
+static int
+match_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+  struct LockMatch *match = cls;
+  struct Lock *lock = value;
+
+  if ( (match->lock_num == lock->lock_num) 
+       && (0 == strcmp (match->domain_name, lock->domain_name)) )
+  {
+    match->matched_entry = lock;    
+    return GNUNET_NO;
+  }
+  return GNUNET_YES;
+}
+
+
 /**
  * Function to search for a lock in the global lock hashmap
  *
@@ -203,33 +251,23 @@ get_key (const char *domain_name,
  * @param lock_num the number of the lock
  * @return the lock if found; NULL if not
  */
-static inline struct Lock *
+static struct Lock *
 find_lock (const char *domain_name,
            const uint32_t lock_num)
               
 {
-  struct Lock *matched_lock;
+  struct LockMatch match;
   struct GNUNET_HashCode key;
 
-  matched_lock = NULL;
-  int match_lock (void *cls,
-                  const GNUNET_HashCode *key,
-                  void *value)
-  {
-    matched_lock = value;
-
-    if ((lock_num == matched_lock->lock_num)
-        && (0 == strcmp (domain_name, matched_lock->domain_name)))
-      return GNUNET_NO;
-    matched_lock = NULL;
-    return GNUNET_YES;
-  }
+  match.lock_num = lock_num;
+  match.domain_name = domain_name;
+  match.matched_entry = NULL;
   get_key (domain_name, lock_num, &key);
   GNUNET_CONTAINER_multihashmap_get_multiple (lock_map,
                                               &key,
-                                              &match_lock,
-                                              NULL);
-  return matched_lock;
+                                              &match_iterator,
+                                              &match);
+  return match.matched_entry;
 }
 
 
@@ -240,7 +278,7 @@ find_lock (const char *domain_name,
  * @param lock_num the lock number
  * @return pointer to the lock structure which is added to lock map
  */
-static inline struct Lock *
+static struct Lock *
 add_lock (const char *domain_name, 
           uint32_t lock_num)
 {
@@ -266,15 +304,16 @@ add_lock (const char *domain_name,
 
 
 /**
- * Removes a lock from the lock map
+ * Removes a lock from the lock map. The WaitList of the lock should be empty
  *
  * @param lock the lock to remove
  */
-static inline void
+static void
 remove_lock (struct Lock *lock)
 {
   struct GNUNET_HashCode key;
-
+  
+  GNUNET_assert (NULL == lock->wl_head);
   get_key (lock->domain_name,
            lock->lock_num,
            &key);
@@ -296,7 +335,7 @@ remove_lock (struct Lock *lock)
  * @param lock the lock which has to be matched
  * @return the matching LockList entry; NULL if no match is found
  */
-static inline struct LockList *
+static struct LockList *
 cl_ll_find_lock (struct ClientList *cl_entry,
                  const struct Lock *lock)
 {
@@ -318,7 +357,7 @@ cl_ll_find_lock (struct ClientList *cl_entry,
  * @param cl_entry the client which currently owns this lock
  * @param lock the lock to be added to the cl_entry's lock list
  */
-static inline void
+static void
 cl_ll_add_lock (struct ClientList *cl_entry,
                 struct Lock *lock)
 {
@@ -341,7 +380,7 @@ cl_ll_add_lock (struct ClientList *cl_entry,
  * @param cl_entry the ClientList entry
  * @param ll_entry the LockList entry to be deleted
  */
-static inline void
+static void
 cl_ll_remove_lock (struct ClientList *cl_entry,
                    struct LockList *ll_entry)
 {
@@ -365,7 +404,7 @@ cl_ll_remove_lock (struct ClientList *cl_entry,
  * @return the WaitList entry matching the given cl_entry; NULL if not match
  *           was found
  */
-static inline struct WaitList *
+static struct WaitList *
 lock_wl_find (const struct Lock *lock,
               const struct ClientList *cl_entry)
 {
@@ -388,7 +427,7 @@ lock_wl_find (const struct Lock *lock,
  * @param lock the lock list entry of a lock
  * @param cl_entry the client to queue for the lock's wait list
  */
-static inline void
+static void
 lock_wl_add_client (struct Lock *lock,
                     struct ClientList *cl_entry)
 {
@@ -412,7 +451,7 @@ lock_wl_add_client (struct Lock *lock,
  * @param lock the lock
  * @param wl_entry the wait list entry to be removed
  */
-static inline void
+static void
 lock_wl_remove (struct Lock *lock,
                 struct WaitList *wl_entry)
 {
@@ -432,7 +471,7 @@ lock_wl_remove (struct Lock *lock,
  * @param client the client to be searched for
  * @return the ClientList entry; NULL if the client is not found
  */
-static inline struct ClientList *
+static struct ClientList *
 cl_find_client (const struct GNUNET_SERVER_Client *client)                
 {
   struct ClientList *current;
@@ -450,7 +489,7 @@ cl_find_client (const struct GNUNET_SERVER_Client *client)
  * @param client the client to be appended to the list
  * @return the client list entry which is added to the client list
  */
-static inline struct ClientList *
+static struct ClientList *
 cl_add_client (struct GNUNET_SERVER_Client *client)
 {
   struct ClientList *new_client;
@@ -468,13 +507,14 @@ cl_add_client (struct GNUNET_SERVER_Client *client)
 
 
 /**
- * Delete the given client from the client list
+ * Delete the given client from the client list. The LockList should be empty
  *
  * @param cl_entry the client list entry to delete
  */
-static inline void
+static void
 cl_remove_client (struct ClientList *cl_entry)
 {
+  GNUNET_assert (NULL == cl_entry->ll_head);
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Removing a client from the client list\n");
   GNUNET_SERVER_client_drop (cl_entry->client);
@@ -635,7 +675,6 @@ process_lock_release (struct Lock *lock)
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Giving lock to a client from wait list\n");
   lock->cl_entry = wl_entry->cl_entry;
-  cl_ll_add_lock (wl_entry->cl_entry, lock);
   lock_wl_remove(lock, wl_entry);
   send_success_msg (lock->cl_entry->client,
                     lock->domain_name,
@@ -733,6 +772,7 @@ client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
 {
   struct ClientList *cl_entry;
   struct LockList *ll_entry;
+  struct Lock *lock;
 
   if (NULL == client)
     return;
@@ -743,13 +783,76 @@ client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
     return;
   while (NULL != (ll_entry = cl_entry->ll_head))
   {
-    process_lock_release (ll_entry->lock);
+    lock = ll_entry->lock;
     cl_ll_remove_lock (cl_entry, ll_entry);
+    process_lock_release (lock);
   }
   cl_remove_client (cl_entry);
 }
 
 
+/**
+ * Hashmap Iterator to delete lock entries in hash map
+ *
+ * @param cls NULL
+ * @param key current key code
+ * @param value value in the hash map
+ * @return GNUNET_YES if we should continue to
+ *         iterate,
+ *         GNUNET_NO if not.
+ */
+static int 
+lock_delete_iterator (void *cls,
+                      const struct GNUNET_HashCode * key,
+                      void *value)
+{
+  struct Lock *lock = value;
+
+  GNUNET_assert (NULL != lock);
+  while (NULL != lock->wl_head)
+  {
+    lock_wl_remove (lock, lock->wl_head);
+  }
+  GNUNET_assert (GNUNET_YES == 
+                 GNUNET_CONTAINER_multihashmap_remove(lock_map,
+                                                      key,
+                                                      lock));
+  GNUNET_free (lock->domain_name);
+  GNUNET_free (lock);
+  return GNUNET_YES;
+}
+
+
+/**
+ * Task to clean up and shutdown nicely
+ *
+ * @param cls NULL
+ * @param tc the TaskContext from scheduler
+ */
+static void
+shutdown_task (void *cls,
+               const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Shutting down lock manager\n");
+  /* Clean the global ClientList */
+  while (NULL != cl_head)
+  {
+    while (NULL != cl_head->ll_head) /* Clear the LockList */
+    {
+      cl_ll_remove_lock (cl_head, cl_head->ll_head);
+    }
+    cl_remove_client (cl_head);
+  }
+  /* Clean the global hash table */
+  GNUNET_CONTAINER_multihashmap_iterate (lock_map,
+                                         &lock_delete_iterator,
+                                         NULL);
+  GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (lock_map));
+  GNUNET_CONTAINER_multihashmap_destroy (lock_map);
+}
+
+
 /**
  * Lock manager setup
  *
@@ -774,6 +877,9 @@ lockmanager_run (void *cls,
                                    &client_disconnect_cb,
                                    NULL);
   lock_map = GNUNET_CONTAINER_multihashmap_create (30);
+  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+                                &shutdown_task,
+                                NULL);
 }