cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

llist.c (2602B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Lock-less NULL terminated single linked list
      4 *
      5 * The basic atomic operation of this list is cmpxchg on long.  On
      6 * architectures that don't have NMI-safe cmpxchg implementation, the
      7 * list can NOT be used in NMI handlers.  So code that uses the list in
      8 * an NMI handler should depend on CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG.
      9 *
     10 * Copyright 2010,2011 Intel Corp.
     11 *   Author: Huang Ying <ying.huang@intel.com>
     12 */
     13#include <linux/kernel.h>
     14#include <linux/export.h>
     15#include <linux/llist.h>
     16
     17
     18/**
     19 * llist_add_batch - add several linked entries in batch
     20 * @new_first:	first entry in batch to be added
     21 * @new_last:	last entry in batch to be added
     22 * @head:	the head for your lock-less list
     23 *
     24 * Return whether list is empty before adding.
     25 */
     26bool llist_add_batch(struct llist_node *new_first, struct llist_node *new_last,
     27		     struct llist_head *head)
     28{
     29	struct llist_node *first;
     30
     31	do {
     32		new_last->next = first = READ_ONCE(head->first);
     33	} while (cmpxchg(&head->first, first, new_first) != first);
     34
     35	return !first;
     36}
     37EXPORT_SYMBOL_GPL(llist_add_batch);
     38
     39/**
     40 * llist_del_first - delete the first entry of lock-less list
     41 * @head:	the head for your lock-less list
     42 *
     43 * If list is empty, return NULL, otherwise, return the first entry
     44 * deleted, this is the newest added one.
     45 *
     46 * Only one llist_del_first user can be used simultaneously with
     47 * multiple llist_add users without lock.  Because otherwise
     48 * llist_del_first, llist_add, llist_add (or llist_del_all, llist_add,
     49 * llist_add) sequence in another user may change @head->first->next,
     50 * but keep @head->first.  If multiple consumers are needed, please
     51 * use llist_del_all or use lock between consumers.
     52 */
     53struct llist_node *llist_del_first(struct llist_head *head)
     54{
     55	struct llist_node *entry, *old_entry, *next;
     56
     57	entry = smp_load_acquire(&head->first);
     58	for (;;) {
     59		if (entry == NULL)
     60			return NULL;
     61		old_entry = entry;
     62		next = READ_ONCE(entry->next);
     63		entry = cmpxchg(&head->first, old_entry, next);
     64		if (entry == old_entry)
     65			break;
     66	}
     67
     68	return entry;
     69}
     70EXPORT_SYMBOL_GPL(llist_del_first);
     71
     72/**
     73 * llist_reverse_order - reverse order of a llist chain
     74 * @head:	first item of the list to be reversed
     75 *
     76 * Reverse the order of a chain of llist entries and return the
     77 * new first entry.
     78 */
     79struct llist_node *llist_reverse_order(struct llist_node *head)
     80{
     81	struct llist_node *new_head = NULL;
     82
     83	while (head) {
     84		struct llist_node *tmp = head;
     85		head = head->next;
     86		tmp->next = new_head;
     87		new_head = tmp;
     88	}
     89
     90	return new_head;
     91}
     92EXPORT_SYMBOL_GPL(llist_reverse_order);