view include/jeffpc/synch.h @ 757:ac902673ea0a

synch: store synchronization primitive type in info struct Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
date Thu, 25 Jul 2019 12:32:05 -0400
parents 607f480900f2
children 2456b4bf6737
line wrap: on
line source

/*
 * Copyright (c) 2011-2019 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#ifndef __JEFFPC_SYNCH_H
#define __JEFFPC_SYNCH_H

#include <stdbool.h>
#include <stdint.h>
#include <pthread.h>

#include <jeffpc/config.h>

struct lock_class {
	const char *name;
#ifdef JEFFPC_LOCK_TRACKING
	size_t ndeps;
	struct lock_class *deps[JEFFPC_LOCK_DEP_COUNT];
#endif
};

#define LOCK_CLASS(n)	struct lock_class n = { .name = #n };

struct lock_context {
	union {
		/* mutex/cond/rwlock */
		struct {
			const char *condname; /* cond */
			const char *lockname; /* mutex or rwlock */
		};
		/* barrier */
		const char *barname; /* barrier */
	};
	const char *file;
	int line;
};

struct lock_info {
	uintptr_t magic;
	unsigned int type;
};

struct lock {
	struct lock_info info;
	pthread_mutex_t lock;
#ifdef JEFFPC_LOCK_TRACKING
	struct lock_class *lc;
	const char *name;
#endif
};

struct rwlock {
	struct lock_info info;
	pthread_rwlock_t lock;
};

struct cond {
	struct lock_info info;
	pthread_cond_t cond;
};

struct barrier {
	pthread_barrier_t bar;
};

/* the API */
#define MXINIT(l, lc)	do { \
				struct lock_context mx_ctx = { \
					.lockname = #l, \
					.file = __FILE__, \
					.line = __LINE__, \
				}; \
				mxinit(&mx_ctx, (l), (lc)); \
			 } while (0)
#define MXDESTROY(l)	do { \
				struct lock_context mx_ctx = { \
					.lockname = #l, \
					.file = __FILE__, \
					.line = __LINE__, \
				}; \
				mxdestroy(&mx_ctx, (l)); \
			} while (0)
#define MXLOCK(l)	do { \
				struct lock_context mx_ctx = { \
					.lockname = #l, \
					.file = __FILE__, \
					.line = __LINE__, \
				}; \
				mxlock(&mx_ctx, (l)); \
			} while (0)
#define MXUNLOCK(l)	do { \
				struct lock_context mx_ctx = { \
					.lockname = #l, \
					.file = __FILE__, \
					.line = __LINE__, \
				}; \
				mxunlock(&mx_ctx, (l)); \
			} while (0)
#define RWINIT(l)	do { \
				struct lock_context rw_ctx = { \
					.lockname = #l, \
					.file = __FILE__, \
					.line = __LINE__, \
				}; \
				rwinit(&rw_ctx, (l)); \
			} while (0)
#define RWDESTROY(l)	do { \
				struct lock_context rw_ctx = { \
					.lockname = #l, \
					.file = __FILE__, \
					.line = __LINE__, \
				}; \
				rwdestroy(&rw_ctx, (l)); \
			} while (0)
#define RWLOCK(l, wr)	do { \
				struct lock_context rw_ctx = { \
					.lockname = #l, \
					.file = __FILE__, \
					.line = __LINE__, \
				}; \
				rwlock(&rw_ctx, (l), (wr)); \
			} while (0)
#define RWUNLOCK(l)	do { \
				struct lock_context rw_ctx = { \
					.lockname = #l, \
					.file = __FILE__, \
					.line = __LINE__, \
				}; \
				rwunlock(&rw_ctx, (l)); \
			} while (0)
#define CONDINIT(c)	do { \
				struct lock_context cond_ctx = { \
					.condname = #c, \
					.file = __FILE__, \
					.line = __LINE__, \
				}; \
				condinit(&cond_ctx, (c)); \
			} while (0)
#define CONDDESTROY(c)	do { \
				struct lock_context cond_ctx = { \
					.condname = #c, \
					.file = __FILE__, \
					.line = __LINE__, \
				}; \
				conddestroy(&cond_ctx, (c)); \
			} while (0)
#define CONDWAIT(c, m)	do { \
				struct lock_context cond_ctx = { \
					.condname = #c, \
					.lockname = #m, \
					.file = __FILE__, \
					.line = __LINE__, \
				}; \
				condwait(&cond_ctx, (c), (m)); \
			} while (0)
#define CONDTIMEDWAIT_NSEC(c, m, t) \
			do { \
				struct lock_context cond_ctx = { \
					.condname = #c, \
					.lockname = #m, \
					.file = __FILE__, \
					.line = __LINE__, \
				}; \
				condtimedwait(&cond_ctx, (c), (m), (t)); \
			} while (0)
#define CONDTIMEDWAIT_SEC(c, m, t) \
			CONDTIMEDWAIT_NSEC((c), (m), (t) * 1000000000ull)
#define CONDTIMEDWAIT_SPEC(c, m, t) \
			do { \
				struct time_spec tmp = *(t); \
				CONDTIMEDWAIT_NSEC((c), (m), \
						   (tmp.tv_sec * 1000000000ull) + \
						   tmp->tv_nsec); \
			} while (0)
#define CONDSIG(c)	do { \
				struct lock_context cond_ctx = { \
					.condname = #c, \
					.file = __FILE__, \
					.line = __LINE__, \
				}; \
				condsig(&cond_ctx, (c)); \
			} while (0)
#define CONDBCAST(c)	do { \
				struct lock_context cond_ctx = { \
					.condname = #c, \
					.file = __FILE__, \
					.line = __LINE__, \
				}; \
				condbcast(&cond_ctx, (c)); \
			} while (0)
#define BARRIERINIT(b, c) \
			do { \
				struct lock_context bar_ctx = { \
					.barname = #b, \
					.file = __FILE__, \
					.line = __LINE__, \
				}; \
				barrierinit(&bar_ctx, (b), (c)); \
			} while (0)
#define BARRIERDESTROY(b) \
			do { \
				struct lock_context bar_ctx = { \
					.barname = #b, \
					.file = __FILE__, \
					.line = __LINE__, \
				}; \
				barrierdestroy(&bar_ctx, (b)); \
			} while (0)
#define BARRIERWAIT(b)	do { \
				struct lock_context bar_ctx = { \
					.barname = #b, \
					.file = __FILE__, \
					.line = __LINE__, \
				}; \
				barrierwait(&bar_ctx, (b)); \
			} while (0)

/* assert that this thread is not holding any locks */
#ifdef JEFFPC_LOCK_TRACKING
extern void lockdep_no_locks(void);
#else
#define lockdep_no_locks()	do { } while (0)
#endif

/* Do *NOT* use directly */
extern void mxinit(const struct lock_context *where, struct lock *m,
		   struct lock_class *lc);
extern void mxdestroy(const struct lock_context *where, struct lock *m);
extern void mxlock(const struct lock_context *where, struct lock *m);
extern void mxunlock(const struct lock_context *where, struct lock *m);

extern void rwinit(const struct lock_context *where, struct rwlock *l);
extern void rwdestroy(const struct lock_context *where, struct rwlock *l);
extern void rwlock(const struct lock_context *where, struct rwlock *l, bool wr);
extern void rwunlock(const struct lock_context *where, struct rwlock *l);

extern void condinit(const struct lock_context *where, struct cond *c);
extern void conddestroy(const struct lock_context *where, struct cond *c);
extern void condwait(const struct lock_context *where, struct cond *c,
		     struct lock *m);
extern int condtimedwait(const struct lock_context *where, struct cond *c,
			 struct lock *m, const uint64_t reltime);
extern void condsig(const struct lock_context *where, struct cond *c);
extern void condbcast(const struct lock_context *where, struct cond *c);

extern void barrierinit(const struct lock_context *where, struct barrier *b,
			unsigned count);
extern void barrierdestroy(const struct lock_context *where, struct barrier *b);
extern bool barrierwait(const struct lock_context *where, struct barrier *b);

#endif