Pintos

5. List

5.1 Doubly linked list.

This implementation of a doubly linked list does not require use of dynamically allocated memory. Instead, each structure that is a potential list element must embed a struct list_elem member.All of the list functions operate on these `struct list_elem's. The list_entry macro allows conversion from a struct list_elem back to a structure object that contains it.

For example, suppose there is a needed for a list of struct foo'.struct foo' should contain a `struct list_elem' member, like so:

  struct foo
  {   
      struct list_elem elem;   
      int bar;   
      ...other members... 
  };

Then a list of `struct foo' can be be declared and initialized like so: struct list foo_list;

 list_init (&foo_list);

Our doubly linked lists have two header elements: the "head" just before the first element and the "tail" just after the last element. The prev' link of the front header is null, as is thenext' link of the back header. Their other two links point toward each other via the interior elements of the list.

An empty list looks like this:

                  +------+     +------+
              <---| head |<--->| tail |--->
                  +------+     +------+

A list with two elements in it looks like this:

    +------+     +-------+     +-------+     +------+
<---| head |<--->|   1   |<--->|   2   |<--->| tail |<--->
    +------+     +-------+     +-------+     +------+

The symmetry of this arrangement eliminates lots of special cases in list processing. For example, take a look at list_remove(): it takes only two pointer assignments and no conditionals. That's a lot simpler than the code would be without header elements.

Iteration is a typical situation where it is necessary to convert from a struct list_elem back to its enclosing structure. Here's an example using foo_list:

  struct list_elem *e;

  for (e = list_begin (&foo_list); e != list_end (&foo_list);
       e = list_next (e))
    {
      struct foo *f = list_entry (e, struct foo, elem);
      ...do something with f...
    }

5.2 Glossary of list terms:

    • "front": The first element in a list. Undefined in an empty list. Returned by list_front().
    • "back": The last element in a list. Undefined in an empty list. Returned by list_back().
    • "tail": The element figuratively just after the last element of a list. Well defined even in an empty list. Returned by list_end(). Used as the end sentinel for an iteration from front to back.
    • "beginning": In a non-empty list, the front. In an empty list, the tail. Returned by list_begin(). Used as the starting point for an iteration from front to back.
    • "head": The element figuratively just before the first element of a list. Well defined even in an empty list. Returned by list_rend(). Used as the end sentinel for an iteration from back to front.
    • "reverse beginning": In a non-empty list, the back. In an empty list, the head. Returned by list_rbegin(). Used as the starting point for an iteration from back to front.
    • "interior element": An element that is not the head or tail, that is, a real list element. An empty list does not have any interior elements.

5.3 List Functions

'kernerl/list.c' implements several functions:

  • A important method we must comprehend:

    #define list_entry(LIST_ELEM, STRUCT, MEMBER) \

          ((STRUCT *) ((uint8_t *) &(LIST_ELEM)->next     \
    
                      - offsetof (STRUCT, MEMBER.next)))
    

Converts pointer to list element LIST_ELEM into a pointer to the structure that LIST_ELEM is embedded inside. Supply the name of the outer structure STRUCT and the member name MEMBER of the list element. See the big comment at the top of the file for an example.

  • void list_init (struct list *);

Initializes LIST as an empty list.

  • struct list_elem *list_begin (struct list *);

Returns the beginning of LIST.

  • struct list_elem *list_next (struct list_elem *);

Returns the element after ELEM in its list. If ELEM is the last element in its list, returns the list tail. Results are undefined if ELEM is itself a list tail.

  • struct list_elem *list_end (struct list *);

Returns LIST's tail.

  • struct list_elem *list_rbegin (struct list *);

Returns the LIST's reverse beginning, for iterating through LIST in reverse order, from back to front.

  • struct list_elem *list_prev (struct list_elem *);

Returns the element before ELEM in its list. If ELEM is the first element in its list, returns the list head. Results are undefined if ELEM is itself a list head.

  • struct list_elem *list_rend (struct list *);

Returns LIST's head.

list_rend() is often used in iterating through a list in reverse order, from back to front. Here's typical usage, following the example from the top of list.h:

  for (e = list_rbegin (&foo_list); e != list_rend (&foo_list);
       e = list_prev (e))
    {
      struct foo *f = list_entry (e, struct foo, elem);
      ...do something with f...
    }
  • struct list_elem *list_head (struct list *);

Return's LIST's head

  • struct list_elem *list_tail (struct list *);

Return's LIST's tail.

  • void list_insert (struct list_elem , struct list_elem );

Inserts ELEM just before BEFORE, which may be either an interior element or a tail. The latter case is equivalent to list_push_back().

  • void list_splice (struct list_elem before, struct list_elem first, struct list_elem *last);

Removes elements FIRST though LAST (exclusive) from their current list, then inserts them just before BEFORE, which may be either an interior element or a tail.

  • void list_push_front (struct list , struct list_elem );

Inserts ELEM at the beginning of LIST, so that it becomes the front in LIST.

  • void list_push_back (struct list , struct list_elem );

Inserts ELEM at the end of LIST, so that it becomes the back in LIST.

  • struct list_elem *list_remove (struct list_elem *);

Removes ELEM from its list and returns the element that followed it. Undefined behavior if ELEM is not in a list.

  • struct list_elem *list_pop_front (struct list *);

Removes the front element from LIST and returns it. Undefined behavior if LIST is empty before removal.

  • struct list_elem *list_pop_back (struct list *);

Removes the back element from LIST and returns it. Undefined behavior if LIST is empty before removal.

  • struct list_elem *list_front (struct list *);

Returns the front element in LIST. Undefined behavior if LIST is empty.

  • struct list_elem *list_back (struct list *);

Returns the back element in LIST. Undefined behavior if LIST is empty.

  • size_t list_size (struct list *);

Returns the number of elements in LIST. Runs in O(n) in the number of elements.

  • bool list_empty(struct list *);

Returns true if LIST is empty, false otherwise.

  • void list_reverse (struct list *);

Reverses the order of LIST.

  • typedef bool list_less_func (const struct list_elem a,const struct list_elem b, void *aux);

We need to rewrite this function when we need:

eg:

bool

thread_less_func(struct list_elem *a, struct list_elem *b, void *aux) {

  return list_entry(a,struct thread,elem)->priority >

         list_entry(b,struct thread,elem)->priority;

}
  • void list_sort (struct list , list_less_func , void *aux);

    Sorts LIST according to LESS given auxiliary data AUX, using a natural iterative merge sort that runs in O(n lg n) time and O(1) space in the number of elements in LIST.

  • void list_insert_ordered (struct list , struct list_elem , list_less_func , void aux);

Inserts ELEM in the proper position in LIST, which must be sorted according to LESS given auxiliary data AUX. Runs in O(n) average case in the number of elements in LIST.

  • void list_unique (struct list , struct list duplicates, list_less_func , void aux);

Iterates through LIST and removes all but the first in each set of adjacent elements that are equal according to LESS given auxiliary data AUX. If DUPLICATES is non-null, then the elements from LIST are appended to DUPLICATES.

  • struct list_elem *list_max (struct list , list_less_func , void *aux);

Returns the element in LIST with the largest value according to LESS given auxiliary data AUX. If there is more than one maximum, returns the one that appears earlier in the list. If the list is empty, returns its tail.

  • struct list_elem *list_min (struct list , list_less_func , void *aux);

Returns the element in LIST with the smallest value according to LESS given auxiliary data AUX. If there is more than one minimum, returns the one that appears earlier in the list. If the list is empty, returns its tail.