123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- /*-------------------------------------------------------------------------
- *
- * proclist.h
- * operations on doubly-linked lists of pgprocnos
- *
- * The interface is similar to dlist from ilist.h, but uses pgprocno instead
- * of pointers. This allows proclist_head to be mapped at different addresses
- * in different backends.
- *
- * See proclist_types.h for the structs that these functions operate on. They
- * are separated to break a header dependency cycle with proc.h.
- *
- * Portions Copyright (c) 2016-2022, PostgreSQL Global Development Group
- *
- * IDENTIFICATION
- * src/include/storage/proclist.h
- *-------------------------------------------------------------------------
- */
- #ifndef PROCLIST_H
- #define PROCLIST_H
- #include "storage/proc.h"
- #include "storage/proclist_types.h"
- /*
- * Initialize a proclist.
- */
- static inline void
- proclist_init(proclist_head *list)
- {
- list->head = list->tail = INVALID_PGPROCNO;
- }
- /*
- * Is the list empty?
- */
- static inline bool
- proclist_is_empty(proclist_head *list)
- {
- return list->head == INVALID_PGPROCNO;
- }
- /*
- * Get a pointer to a proclist_node inside a given PGPROC, given a procno and
- * the proclist_node field's offset within struct PGPROC.
- */
- static inline proclist_node *
- proclist_node_get(int procno, size_t node_offset)
- {
- char *entry = (char *) GetPGProcByNumber(procno);
- return (proclist_node *) (entry + node_offset);
- }
- /*
- * Insert a process at the beginning of a list.
- */
- static inline void
- proclist_push_head_offset(proclist_head *list, int procno, size_t node_offset)
- {
- proclist_node *node = proclist_node_get(procno, node_offset);
- Assert(node->next == 0 && node->prev == 0);
- if (list->head == INVALID_PGPROCNO)
- {
- Assert(list->tail == INVALID_PGPROCNO);
- node->next = node->prev = INVALID_PGPROCNO;
- list->head = list->tail = procno;
- }
- else
- {
- Assert(list->tail != INVALID_PGPROCNO);
- Assert(list->head != procno);
- Assert(list->tail != procno);
- node->next = list->head;
- proclist_node_get(node->next, node_offset)->prev = procno;
- node->prev = INVALID_PGPROCNO;
- list->head = procno;
- }
- }
- /*
- * Insert a process at the end of a list.
- */
- static inline void
- proclist_push_tail_offset(proclist_head *list, int procno, size_t node_offset)
- {
- proclist_node *node = proclist_node_get(procno, node_offset);
- Assert(node->next == 0 && node->prev == 0);
- if (list->tail == INVALID_PGPROCNO)
- {
- Assert(list->head == INVALID_PGPROCNO);
- node->next = node->prev = INVALID_PGPROCNO;
- list->head = list->tail = procno;
- }
- else
- {
- Assert(list->head != INVALID_PGPROCNO);
- Assert(list->head != procno);
- Assert(list->tail != procno);
- node->prev = list->tail;
- proclist_node_get(node->prev, node_offset)->next = procno;
- node->next = INVALID_PGPROCNO;
- list->tail = procno;
- }
- }
- /*
- * Delete a process from a list --- it must be in the list!
- */
- static inline void
- proclist_delete_offset(proclist_head *list, int procno, size_t node_offset)
- {
- proclist_node *node = proclist_node_get(procno, node_offset);
- Assert(node->next != 0 || node->prev != 0);
- if (node->prev == INVALID_PGPROCNO)
- {
- Assert(list->head == procno);
- list->head = node->next;
- }
- else
- proclist_node_get(node->prev, node_offset)->next = node->next;
- if (node->next == INVALID_PGPROCNO)
- {
- Assert(list->tail == procno);
- list->tail = node->prev;
- }
- else
- proclist_node_get(node->next, node_offset)->prev = node->prev;
- node->next = node->prev = 0;
- }
- /*
- * Check if a process is currently in a list. It must be known that the
- * process is not in any _other_ proclist that uses the same proclist_node,
- * so that the only possibilities are that it is in this list or none.
- */
- static inline bool
- proclist_contains_offset(proclist_head *list, int procno,
- size_t node_offset)
- {
- proclist_node *node = proclist_node_get(procno, node_offset);
- /* If it's not in any list, it's definitely not in this one. */
- if (node->prev == 0 && node->next == 0)
- return false;
- /*
- * It must, in fact, be in this list. Ideally, in assert-enabled builds,
- * we'd verify that. But since this function is typically used while
- * holding a spinlock, crawling the whole list is unacceptable. However,
- * we can verify matters in O(1) time when the node is a list head or
- * tail, and that seems worth doing, since in practice that should often
- * be enough to catch mistakes.
- */
- Assert(node->prev != INVALID_PGPROCNO || list->head == procno);
- Assert(node->next != INVALID_PGPROCNO || list->tail == procno);
- return true;
- }
- /*
- * Remove and return the first process from a list (there must be one).
- */
- static inline PGPROC *
- proclist_pop_head_node_offset(proclist_head *list, size_t node_offset)
- {
- PGPROC *proc;
- Assert(!proclist_is_empty(list));
- proc = GetPGProcByNumber(list->head);
- proclist_delete_offset(list, list->head, node_offset);
- return proc;
- }
- /*
- * Helper macros to avoid repetition of offsetof(PGPROC, <member>).
- * 'link_member' is the name of a proclist_node member in PGPROC.
- */
- #define proclist_delete(list, procno, link_member) \
- proclist_delete_offset((list), (procno), offsetof(PGPROC, link_member))
- #define proclist_push_head(list, procno, link_member) \
- proclist_push_head_offset((list), (procno), offsetof(PGPROC, link_member))
- #define proclist_push_tail(list, procno, link_member) \
- proclist_push_tail_offset((list), (procno), offsetof(PGPROC, link_member))
- #define proclist_pop_head_node(list, link_member) \
- proclist_pop_head_node_offset((list), offsetof(PGPROC, link_member))
- #define proclist_contains(list, procno, link_member) \
- proclist_contains_offset((list), (procno), offsetof(PGPROC, link_member))
- /*
- * Iterate through the list pointed at by 'lhead', storing the current
- * position in 'iter'. 'link_member' is the name of a proclist_node member in
- * PGPROC. Access the current position with iter.cur.
- *
- * The only list modification allowed while iterating is deleting the current
- * node with proclist_delete(list, iter.cur, node_offset).
- */
- #define proclist_foreach_modify(iter, lhead, link_member) \
- for (AssertVariableIsOfTypeMacro(iter, proclist_mutable_iter), \
- AssertVariableIsOfTypeMacro(lhead, proclist_head *), \
- (iter).cur = (lhead)->head, \
- (iter).next = (iter).cur == INVALID_PGPROCNO ? INVALID_PGPROCNO : \
- proclist_node_get((iter).cur, \
- offsetof(PGPROC, link_member))->next; \
- (iter).cur != INVALID_PGPROCNO; \
- (iter).cur = (iter).next, \
- (iter).next = (iter).cur == INVALID_PGPROCNO ? INVALID_PGPROCNO : \
- proclist_node_get((iter).cur, \
- offsetof(PGPROC, link_member))->next)
- #endif /* PROCLIST_H */
|