#include <stdio.h>
#include <string.h>

#ifndef BUGGY
#define BUGGY  1
#endif
#define PRINT0 1
#define PRINT1 0

struct list_head
{
    struct list_head *prev;
    struct list_head *next;
};

#define LIST_INITHEAD(__item)           \
  do {                                  \
    (__item)->prev = (__item);          \
    (__item)->next = (__item);          \
  } while (0)

#define LIST_ADD(__item, __list)        \
  do {                                  \
  printf("X %p %p\n",(__item),(__list)); \
    (__item)->prev = (__list);          \
  printf("Y1 %p %p\n",(__item),(__list)); \
    (__item)->next = (__list)->next;    \
  printf("Y2 %p %p\n",(__item),(__list)); \
    (__list)->next->prev = (__item);    \
  printf("Y3 %p %p\n",(__item),(__list)); \
    (__list)->next = (__item);          \
  printf("Y %p %p\n",(__item),(__list)); \
  } while (0)

#define LIST_DEL(__item)                    \
  do {                                      \
    (__item)->prev->next = (__item)->next;  \
    (__item)->next->prev = (__item)->prev;  \
  } while(0)


#ifndef container_of
#define container_of(ptr, sample, member)       \
    (void *)((char *)(ptr) - ((char *)&(sample)->member - (char *)(sample)))
#endif

#define LIST_FOR_EACH_ENTRY(pos, head, member)          \
   for (pos = container_of((head)->next, pos, member);  \
    &pos->member != (head);                             \
    pos = container_of(pos->member.next, pos, member))

#define LIST_FOR_EACH_ENTRY_SAFE(pos, storage, head, member)    \
   for (pos = container_of((head)->next, pos, member),          \
        storage = container_of(pos->member.next, pos, member);      \
        &pos->member != (head);                                     \
        pos = storage, storage = container_of(storage->member.next, storage, member))

struct toto {
    struct list_head list;
    unsigned         id;
};

void LIST_ADD2(struct list_head *__item, struct list_head *__list)
{
  printf("X %p %p\n",(__item),(__list));
    (__item)->prev = (__list);
  printf("Y1 %p %p\n",(__item),(__list)); 
    (__item)->next = (__list)->next;
  printf("Y2 %p %p\n",(__item),(__list)); 
    (__list)->next->prev = (__item);
  printf("Y3 %p %p\n",(__item),(__list)); 
    (__list)->next = (__item);
  printf("Y %p %p\n",(__item),(__list));
}


__attribute__((noinline)) void buggy(struct toto *toto, struct list_head *list)
{
    struct toto *tmp, *next, *tmp2;
    unsigned i;

#if 0
    LIST_ADD(&toto[3].list, list);
    LIST_ADD(&toto[2].list, list);
#else
    i = 2;
    LIST_FOR_EACH_ENTRY_SAFE(tmp, next, list, list) {
        tmp2 = &toto[i++];
#if BUGGY
        LIST_ADD(&tmp2->list, tmp->list.prev);
#else
        LIST_ADD2(&tmp2->list, tmp->list.prev);
#endif
        LIST_DEL(&tmp->list);
    }
#endif
}

int main(void)
{
    struct toto toto[10], *tmp, *next, *tmp2;
    struct list_head list;
    unsigned i;

    memset(&toto, 0, sizeof(struct toto) * 10);
    for (i = 0; i < 10; i++) {
        toto[i].id = i;
        printf("toto[%d] %p\n",i,&toto[i]);
    }
    LIST_INITHEAD(&list);
    LIST_ADD(&toto[0].list, &list);
    LIST_ADD(&toto[1].list, &list);

#if PRINT0
    printf("before\n");
    LIST_FOR_EACH_ENTRY(tmp, &list, list) {
        printf("list %p %d\n", tmp, tmp->id);
    }
#endif

    buggy(toto, &list);

#if PRINT0
    printf("\nafter\n");
#endif
    i = 2;
    LIST_FOR_EACH_ENTRY(tmp, &list, list) {
#if PRINT0
        printf("list %p %d\n", tmp, tmp->id);
#endif
        if (tmp->id != i++) {
            return -1;
        }
    }
    return 0;
}
