<commit_before>/* $Id$ */

/*
 * Locked lists are thread-safe linked lists.
 */

#ifndef _PFL_LOCKEDLIST_H_
#define _PFL_LOCKEDLIST_H_

#include <stddef.h>

#include "psc_ds/list.h"
#include "psc_util/alloc.h"
#include "psc_util/assert.h"
#include "psc_util/atomic.h"
#include "psc_util/lock.h"

struct psc_lockedlist {
	struct psclist_head	 pll_listhd;
	psc_spinlock_t		*pll_lockp;
	atomic_t		 pll_nitems;
	int			 pll_offset;
	int			 pll_flags;
};

#define PLLF_ALLOCLOCK	(1 << 0)	/* list alloc'd its own lock */

#define PLL_INITIALIZER(pll, type, member, lock)		\
	{ PSCLIST_HEAD_INIT((pll)->pll_listhd), (lock),		\
	  ATOMIC_INIT(0), offsetof(type, member), 0 }

#define pll_init(pll, type, member, lock)			\
	_pll_init((pll), offsetof(type, member), (lock))

static __inline void
_pll_init(struct psc_lockedlist *pll, int offset, psc_spinlock_t *lkp)
{
	INIT_PSCLIST_HEAD(&pll->pll_listhd);
	pll->pll_flags = 0;
	if (lkp)
		pll->pll_lockp = lkp;
	else {
		pll->pll_lockp = PSCALLOC(sizeof(*pll->pll_lockp));
		LOCK_INIT(pll->pll_lockp);
		pll->pll_flags |= PLLF_ALLOCLOCK;
	}
	pll->pll_offset = offset;
	atomic_set(&pll->pll_nitems, 0);
}

static __inline void
pll_destroy(struct psc_lockedlist *pll)
{
	if (pll->pll_flags & PLLF_ALLOCLOCK)
		PSCFREE(pll->pll_lockp);
}

#define pll_nitems(pll)		atomic_read(&(pll)->pll_nitems)

#define pll_add(pll, p)		_pll_add((pll), (p), 0)
#define pll_addstack(pll, p)	_pll_add((pll), (p), 0)
#define pll_addqueue(pll, p)	_pll_add((pll), (p), 1)
#define pll_addhead(pll, p)	_pll_add((pll), (p), 0)
#define pll_addtail(pll, p)	_pll_add((pll), (p), 1)

static __inline void
_pll_add(struct psc_lockedlist *pll, void *p, int tail)
{
	int locked;
	void *e;

	psc_assert(p);
	e = (char *)p + pll->pll_offset;
	locked = reqlock(pll->pll_lockp);
	if (tail)
		psclist_xadd_tail(e, &pll->pll_listhd);
	else
		psclist_xadd_head(e, &pll->pll_listhd);
	atomic_inc(&pll->pll_nitems);
	ureqlock(pll->pll_lockp, locked);
}

static __inline void *
pll_get(struct psc_lockedlist *pll, ptrdiff_t tail)
{
	struct psclist_head *e;
	int locked;

	locked = reqlock(pll->pll_lockp);
	if (psclist_empty(&pll->pll_listhd)) {
		ureqlock(pll->pll_lockp, locked);
		return (NULL);
	}
	if (tail)
		e = psclist_last(&pll->pll_listhd);
	else
		e = psclist_first(&pll->pll_listhd);
	psclist_del(e);
	atomic_dec(&pll->pll_nitems);
	ureqlock(pll->pll_lockp, locked);
	return ((char *)e - pll->pll_offset);
}

static __inline void
pll_remove(struct psc_lockedlist *pll, void *p)
{
	int locked;
	void *e;

	psc_assert(p);
	e = (char *)p + pll->pll_offset;
	locked = reqlock(pll->pll_lockp);
	psclist_del(e);
	atomic_dec(&pll->pll_nitems);
	ureqlock(pll->pll_lockp, locked);<commit_msg>change pll_nitems from atomic -> int just to avoid races against pll_remove; add peeking and stack/queues support on item retrieval, although peeking should rarely be used due to inherent race conditions<commit_after>/* $Id$ */

/*
 * Locked lists are thread-safe linked lists.
 */

#ifndef _PFL_LOCKEDLIST_H_
#define _PFL_LOCKEDLIST_H_

#include <stddef.h>
#include <string.h>

#include "psc_ds/list.h"
#include "psc_util/alloc.h"
#include "psc_util/assert.h"
#include "psc_util/lock.h"

struct psc_lockedlist {
	struct psclist_head	 pll_listhd;
	psc_spinlock_t		*pll_lockp;
	int			 pll_nitems;
	int			 pll_offset;
	int			 pll_flags;
};

#define PLLF_ALLOCLOCK	(1 << 0)	/* list alloc'd its own lock */

#define PLL_INITIALIZER(pll, type, member, lock)		\
	{ PSCLIST_HEAD_INIT((pll)->pll_listhd), (lock),		\
	  0, offsetof(type, member), 0 }

#define pll_init(pll, type, member, lock)			\
	_pll_init((pll), offsetof(type, member), (lock))

static __inline void
_pll_init(struct psc_lockedlist *pll, int offset, psc_spinlock_t *lkp)
{
	memset(pll, 0, sizeof(*pll));
	INIT_PSCLIST_HEAD(&pll->pll_listhd);
	if (lkp)
		pll->pll_lockp = lkp;
	else {
		pll->pll_lockp = PSCALLOC(sizeof(*pll->pll_lockp));
		LOCK_INIT(pll->pll_lockp);
		pll->pll_flags |= PLLF_ALLOCLOCK;
	}
	pll->pll_offset = offset;
}

static __inline void
pll_destroy(struct psc_lockedlist *pll)
{
	if (pll->pll_flags & PLLF_ALLOCLOCK)
		PSCFREE(pll->pll_lockp);
}

static __inline int
pll_nitems(struct psc_lockedlist *pll)
{
	int n, locked;

	locked = reqlock(pll->pll_lockp);
	n = pll->pll_nitems;
	ureqlock(pll->pll_lockp, locked);
	return (n);
}

#define pll_add(pll, p)		_pll_add((pll), (p), 0)
#define pll_addstack(pll, p)	_pll_add((pll), (p), 0)
#define pll_addqueue(pll, p)	_pll_add((pll), (p), 1)
#define pll_addhead(pll, p)	_pll_add((pll), (p), 0)
#define pll_addtail(pll, p)	_pll_add((pll), (p), 1)

static __inline void
_pll_add(struct psc_lockedlist *pll, void *p, int tail)
{
	int locked;
	void *e;

	psc_assert(p);
	e = (char *)p + pll->pll_offset;
	locked = reqlock(pll->pll_lockp);
	if (tail)
		psclist_xadd_tail(e, &pll->pll_listhd);
	else
		psclist_xadd_head(e, &pll->pll_listhd);
	pll->pll_nitems++;
	ureqlock(pll->pll_lockp, locked);
}

#define PLLF_HEAD	(1 << 0)
#define PLLF_STACK	(1 << 0)
#define PLLF_TAIL	(1 << 1)
#define PLLF_QUEUE	(1 << 1)
#define PLLF_PEEK	(1 << 2)

static __inline void *
_pll_get(struct psc_lockedlist *pll, int flags)
{
	struct psclist_head *e;
	int locked;

	psc_assert((flags & PLLF_HEAD) ^ (flags & PLLF_TAIL));

	locked = reqlock(pll->pll_lockp);
	if (psclist_empty(&pll->pll_listhd)) {
		ureqlock(pll->pll_lockp, locked);
		return (NULL);
	}
	if (flags & PLLF_TAIL)
		e = psclist_last(&pll->pll_listhd);
	else
		e = psclist_first(&pll->pll_listhd);
	if ((flags & PLLF_PEEK) == 0) {
		psclist_del(e);
		pll->pll_nitems--;
	}
	ureqlock(pll->pll_lockp, locked);
	return ((char *)e - pll->pll_offset);
}

#define pll_get(pll)		_pll_get((pll), PLLF_HEAD)
#define pll_gethd(pll)		_pll_get((pll), PLLF_HEAD)
#define pll_gettail(pll)	_pll_get((pll), PLLF_TAIL)
#define pll_gethdpeek(pll)	_pll_get((pll), PLLF_HEAD | PLLF_PEEK)

static __inline void
pll_remove(struct psc_lockedlist *pll, void *p)
{
	int locked;
	void *e;

	psc_assert(p);
	e = (char *)p + pll->pll_offset;
	locked = reqlock(pll->pll_lockp);
	psclist_del(e);
	pll->pll_nitems--;
	ureqlock(pll->pll_lockp, locked);
{'fraction_non_alphanumeric': 0.15460526315789475, 'fraction_numerical': 0.005263157894736842, 'mean_word_length': 5.198776758409786, 'pattern_counts': {'":': 0, '<': 20, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '242177', 'n_tokens_mistral': 2983, 'n_tokens_neox': 2663, 'n_words': 539}