From: lon Date: Thu, 5 Oct 2000 19:15:40 +0000 (+0000) Subject: Partial rewrite of notify list handling functions. Eliminated bogus, run-off X-Git-Tag: nfs-utils-0-3~27 X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=commitdiff_plain;h=0fc49952e287c0f2387ba019b5d8e295e2411354 Partial rewrite of notify list handling functions. Eliminated bogus, run-off -end-of-list bug when calling nlist_insert_timer. Added lots of comments. --- diff --git a/utils/statd/notlist.c b/utils/statd/notlist.c index bc0c294..0ef5491 100644 --- a/utils/statd/notlist.c +++ b/utils/statd/notlist.c @@ -2,6 +2,8 @@ * Copyright (C) 1995, 1997-1999 Jeffrey A. Uphoff * Modified by Olaf Kirch, 1996. * Modified by H.J. Lu, 1998. + * Modified by Lon Hohberger, Oct. 2000. + * - Fixed memory leaks, run-off-end problems, etc. * * NSM for Linux. */ @@ -17,7 +19,35 @@ #include "statd.h" #include "notlist.h" -notify_list * + +#ifdef DEBUG +/* + * LH - The linked list code had some bugs. Used this to help debug + * new code. + */ +static void +plist(notify_list *head, int en) +{ + /* case where we ran off the end */ + if (!head) return; + + printf("Entry %d: %s\n",en, NL_MON_NAME(head)); + plist(head->next, ++en); +} + +static void +nlist_print(notify_list **head) +{ + printf("--- Begin notify list dump ---\n"); + plist(*head,1); + printf("--- End notify list dump ---\n"); +} +#endif /* DEBUG */ + +/* + * Allocate memory and set up a new notify list entry. + */ +notify_list * nlist_new(char *my_name, char *mon_name, int state) { notify_list *new; @@ -29,51 +59,128 @@ nlist_new(char *my_name, char *mon_name, int state) NL_TIMES(new) = MAX_TRIES; NL_STATE(new) = state; if (!(NL_MY_NAME(new) = xstrdup(my_name)) - || !(NL_MON_NAME(new) = xstrdup(mon_name))) + || !(NL_MON_NAME(new) = xstrdup(mon_name))) return NULL; return new; } -void +/* + * Insert *entry into a notify list at the point specified by + * **head. This can be in the middle. However, we do not handle + * list _append_ in this function; rather, the only place we should + * have to worry about this case is in nlist_insert_timer below. + * - entry must not be NULL. + */ +void nlist_insert(notify_list **head, notify_list *entry) { - notify_list *next = *head, *tail = entry; + if (*head) { + /* + * Cases where we're prepending a non-empty list + * or inserting possibly in the middle somewhere (eg, + * nlist_insert_timer...) + */ + entry->next = (*head); /* Forward pointer */ + entry->prev = (*head)->prev; /* Back pointer */ + (*head)->prev = entry; /* head's new back pointer */ + } - /* Find end of list to be inserted */ - while (tail->next) - tail = tail->next; + /* Common to all cases, including new list creation */ + *head = entry; /* New head */ - if (next) - next->prev = tail; - tail->next = next; - *head = entry; +#ifdef DEBUG + nlist_print(head); +#endif } -void +/* + * (re)insert *entry into notify_list **head. This requires that + * NL_WHEN(entry) has been set (usually, this is time() + 5 seconds). + * - entry must not be NULL + * + * LH - This used to cause (a) a memory leak and (b) dropped notify-list + * entries. The pointer ran off the end of the list, and changed the + * head-end to point to the new, one-entry list. All other entries became garbage. + * + * FIXME: Optimize this function. (I'll work on it - LH) + */ +void nlist_insert_timer(notify_list **head, notify_list *entry) { - /* Find first entry with higher timeout value */ - while (*head && NL_WHEN(*head) <= NL_WHEN(entry)) - head = &(*head)->next; - nlist_insert(head, entry); + notify_list *spot = *head, /* Insertion location */ + /* ...Start at head */ + *back = NULL; /* Back pointer */ + + + /* Find first entry with higher timeout value or end of list */ + while (spot && NL_WHEN(spot) <= NL_WHEN(entry)) { + /* + * Keep the back pointer in case we + * run off the end... (see below) + */ + back = spot; + spot = spot->next; + } + + if (spot == (*head)) { + /* + * case where we're prepending an empty or non-empty + * list or inserting in the middle somewhere. Pass + * the real head of the list, since we'll be changing + * during the insert... + */ + nlist_insert(head, entry); + } else { + /* all other cases - don't move the real head pointer */ + nlist_insert(&spot, entry); + + /* + * If spot == entry, then spot was NULL when we called + * nlist_insert. This happened because we had run off + * the end of the list. Append entry to original list. + */ + if (spot == entry) { + back->next = entry; + entry->prev = back; + } + } } -void +/* + * Remove *entry from the list pointed to by **head. + * Do not destroy *entry. This is normally done before + * a re-insertion with a timer, but can be done anywhere. + * - entry must not be NULL. + */ +void nlist_remove(notify_list **head, notify_list *entry) { notify_list *prev = entry->prev, *next = entry->next; - if (next) + if (next) { next->prev = prev; - if (prev) - prev->next = next; - else + } + + if (prev) { + /* Case(s) where entry isn't at the front */ + prev->next = next; + } else { + /* cases where entry is at the front */ *head = next; + } + entry->next = entry->prev = NULL; +#ifdef DEBUG + nlist_print(head); +#endif } +/* + * Clone an entry in the notify list - + * - entry must not be NULL + */ notify_list * nlist_clone(notify_list *entry) { @@ -89,10 +196,16 @@ nlist_clone(notify_list *entry) return new; } -void +/* + * Destroy an entry in a notify list and free the memory. + * If *head is NULL, just free the entry. This would be + * done only when we know entry isn't in any list. + * - entry must not be NULL. + */ +void nlist_free(notify_list **head, notify_list *entry) { - if (head) + if (head && (*head)) nlist_remove(head, entry); if (NL_MY_NAME(entry)) free(NL_MY_NAME(entry)); @@ -101,7 +214,10 @@ nlist_free(notify_list **head, notify_list *entry) free(entry); } -void +/* + * Destroy an entire notify list + */ +void nlist_kill(notify_list **head) { while (*head)