Commit 60918275 authored by Lennart Poettering's avatar Lennart Poettering
Browse files

initial commit

parents
systemd
*.o
- 8ch indent, no tabs
- structs in MixedCase, variables, functions in lower_case
- the destructors always unregister the object from the next bigger
object, not the other way around
- to minimize strict aliasing violations we prefer unions over casting
- for robustness reasons destructors should be able to destruct
half-initialized objects, too
- error codes are returned as negative Exxx. i.e. return EINVAL. There
are some exceptions: for constructors its is OK to return NULL on
OOM. For lookup functions NULL is fine too for "not found".
CFLAGS=-Wall -Wextra -O0 -g -pipe
LIBS=-lrt
systemd: main.o name.o util.o set.o hashmap.o strv.o job.o manager.o
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
clean:
rm -f *.o systemd
/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "util.h"
#include "hashmap.h"
#include "macro.h"
#define NBUCKETS 127
struct hashmap_entry {
const void *key;
void *value;
struct hashmap_entry *bucket_next, *bucket_previous;
struct hashmap_entry *iterate_next, *iterate_previous;
};
struct Hashmap {
hash_func_t hash_func;
compare_func_t compare_func;
struct hashmap_entry *iterate_list_head, *iterate_list_tail;
unsigned n_entries;
};
#define BY_HASH(h) ((struct hashmap_entry**) ((uint8_t*) (h) + ALIGN(sizeof(Hashmap))))
unsigned string_hash_func(const void *p) {
unsigned hash = 0;
const char *c;
for (c = p; *c; c++)
hash = 31 * hash + (unsigned) *c;
return hash;
}
int string_compare_func(const void *a, const void *b) {
return strcmp(a, b);
}
unsigned trivial_hash_func(const void *p) {
return PTR_TO_UINT(p);
}
int trivial_compare_func(const void *a, const void *b) {
return a < b ? -1 : (a > b ? 1 : 0);
}
Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func) {
Hashmap *h;
if (!(h = malloc0(ALIGN(sizeof(Hashmap)) + NBUCKETS * ALIGN(sizeof(struct hashmap_entry*)))))
return NULL;
h->hash_func = hash_func ? hash_func : trivial_hash_func;
h->compare_func = compare_func ? compare_func : trivial_compare_func;
h->n_entries = 0;
h->iterate_list_head = h->iterate_list_tail = NULL;
return h;
}
static void remove_entry(Hashmap *h, struct hashmap_entry *e) {
assert(h);
assert(e);
/* Remove from iteration list */
if (e->iterate_next)
e->iterate_next->iterate_previous = e->iterate_previous;
else
h->iterate_list_tail = e->iterate_previous;
if (e->iterate_previous)
e->iterate_previous->iterate_next = e->iterate_next;
else
h->iterate_list_head = e->iterate_next;
/* Remove from hash table bucket list */
if (e->bucket_next)
e->bucket_next->bucket_previous = e->bucket_previous;
if (e->bucket_previous)
e->bucket_previous->bucket_next = e->bucket_next;
else {
unsigned hash = h->hash_func(e->key) % NBUCKETS;
BY_HASH(h)[hash] = e->bucket_next;
}
free(e);
assert(h->n_entries >= 1);
h->n_entries--;
}
void hashmap_free(Hashmap*h) {
if (!h)
return;
while (h->iterate_list_head)
remove_entry(h, h->iterate_list_head);
free(h);
}
static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *key) {
struct hashmap_entry *e;
assert(h);
assert(hash < NBUCKETS);
for (e = BY_HASH(h)[hash]; e; e = e->bucket_next)
if (h->compare_func(e->key, key) == 0)
return e;
return NULL;
}
int hashmap_put(Hashmap *h, const void *key, void *value) {
struct hashmap_entry *e;
unsigned hash;
assert(h);
hash = h->hash_func(key) % NBUCKETS;
if (hash_scan(h, hash, key))
return -EEXIST;
if (!(e = new(struct hashmap_entry, 1)))
return -ENOMEM;
e->key = key;
e->value = value;
/* Insert into hash table */
e->bucket_next = BY_HASH(h)[hash];
e->bucket_previous = NULL;
if (BY_HASH(h)[hash])
BY_HASH(h)[hash]->bucket_previous = e;
BY_HASH(h)[hash] = e;
/* Insert into iteration list */
e->iterate_previous = h->iterate_list_tail;
e->iterate_next = NULL;
if (h->iterate_list_tail) {
assert(h->iterate_list_head);
h->iterate_list_tail->iterate_next = e;
} else {
assert(!h->iterate_list_head);
h->iterate_list_head = e;
}
h->iterate_list_tail = e;
h->n_entries++;
assert(h->n_entries >= 1);
return 0;
}
void* hashmap_get(Hashmap *h, const void *key) {
unsigned hash;
struct hashmap_entry *e;
if (!h)
return NULL;
hash = h->hash_func(key) % NBUCKETS;
if (!(e = hash_scan(h, hash, key)))
return NULL;
return e->value;
}
void* hashmap_remove(Hashmap *h, const void *key) {
struct hashmap_entry *e;
unsigned hash;
void *data;
if (!h)
return NULL;
hash = h->hash_func(key) % NBUCKETS;
if (!(e = hash_scan(h, hash, key)))
return NULL;
data = e->value;
remove_entry(h, e);
return data;
}
void *hashmap_iterate(Hashmap *h, void **state, const void **key) {
struct hashmap_entry *e;
assert(state);
if (!h)
goto at_end;
if (*state == (void*) -1)
goto at_end;
if (!*state && !h->iterate_list_head)
goto at_end;
e = *state ? *state : h->iterate_list_head;
if (e->iterate_next)
*state = e->iterate_next;
else
*state = (void*) -1;
if (key)
*key = e->key;
return e->value;
at_end:
*state = (void *) -1;
if (key)
*key = NULL;
return NULL;
}
void *hashmap_iterate_backwards(Hashmap *h, void **state, const void **key) {
struct hashmap_entry *e;
assert(state);
if (!h)
goto at_beginning;
if (*state == (void*) -1)
goto at_beginning;
if (!*state && !h->iterate_list_tail)
goto at_beginning;
e = *state ? *state : h->iterate_list_tail;
if (e->iterate_previous)
*state = e->iterate_previous;
else
*state = (void*) -1;
if (key)
*key = e->key;
return e->value;
at_beginning:
*state = (void *) -1;
if (key)
*key = NULL;
return NULL;
}
void* hashmap_first(Hashmap *h) {
if (!h)
return NULL;
if (!h->iterate_list_head)
return NULL;
return h->iterate_list_head->value;
}
void* hashmap_last(Hashmap *h) {
if (!h)
return NULL;
if (!h->iterate_list_tail)
return NULL;
return h->iterate_list_tail->value;
}
void* hashmap_steal_first(Hashmap *h) {
void *data;
if (!h)
return NULL;
if (!h->iterate_list_head)
return NULL;
data = h->iterate_list_head->value;
remove_entry(h, h->iterate_list_head);
return data;
}
unsigned hashmap_size(Hashmap *h) {
if (!h)
return 0;
return h->n_entries;
}
bool hashmap_isempty(Hashmap *h) {
if (!h)
return true;
return h->n_entries == 0;
}
/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foohashmaphfoo
#define foohashmaphfoo
#include <stdbool.h>
/* Pretty straightforward hash table implementation. As a minor
* optimization a NULL hashmap object will be treated as empty hashmap
* for all read operations. That way it is not necessary to
* instantiate an object for each Hashmap use. */
typedef struct Hashmap Hashmap;
typedef unsigned (*hash_func_t)(const void *p);
typedef int (*compare_func_t)(const void *a, const void *b);
unsigned string_hash_func(const void *p);
int string_compare_func(const void *a, const void *b);
unsigned trivial_hash_func(const void *p);
int trivial_compare_func(const void *a, const void *b);
Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func);
void hashmap_free(Hashmap*);
int hashmap_put(Hashmap *h, const void *key, void *value);
void* hashmap_get(Hashmap *h, const void *key);
void* hashmap_remove(Hashmap *h, const void *key);
unsigned hashmap_size(Hashmap *h);
bool hashmap_isempty(Hashmap *h);
void *hashmap_iterate(Hashmap *h, void **state, const void **key);
void *hashmap_iterate_backwards(Hashmap *h, void **state, const void **key);
void *hashmap_steal_first(Hashmap *h);
void* hashmap_first(Hashmap *h);
void* hashmap_last(Hashmap *h);
#define HASHMAP_FOREACH(e, h, state) \
for ((state) = NULL, (e) = hashmap_iterate((h), &(state), NULL); (e); (e) = hashmap_iterate((h), &(state), NULL))
#define HASHMAP_FOREACH_BACKWARDS(e, h, state) \
for ((state) = NULL, (e) = hashmap_iterate_backwards((h), &(state), NULL); (e); (e) = hashmap_iterate_backwards((h), &(state), NULL))
#endif
/*-*- Mode: C; c-basic-offset: 8 -*-*/
#include <assert.h>
#include "macro.h"
#include "job.h"
Job* job_new(Manager *m, JobType type, Name *name) {
Job *j;
assert(m);
assert(type < _JOB_TYPE_MAX);
assert(name);
if (!(j = new0(Job, 1)))
return NULL;
j->manager = m;
j->id = m->current_job_id++;
j->type = type;
j->name = name;
/* We don't link it here, that's what job_link() is for */
return j;
}
int job_link(Job *j) {
int r;
assert(j);
assert(!j->linked);
if ((r = hashmap_put(j->manager->jobs, UINT32_TO_PTR(j->id), j)) < 0)
return r;
j->name->meta.job = j;
j->linked = true;
return 0;
}
void job_free(Job *j) {
assert(j);
/* Detach from next 'bigger' objects */
if (j->linked) {
if (j->name && j->name->meta.job == j)
j->name->meta.job = NULL;
hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
}
/* Free data and next 'smaller' objects */
free(j);
}
/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foojobhfoo
#define foojobhfoo
#include <stdbool.h>
#include <inttypes.h>
typedef struct Job Job;
typedef enum JobType JobType;
typedef enum JobMode JobMode;
#include "manager.h"
#include "name.h"
#include "hashmap.h"
#include "list.h"
enum JobType {
JOB_START,
JOB_STOP,
JOB_VERIFY_STARTED,
JOB_RELOAD,
JOB_RESTART,
JOB_TRY_RESTART, /* restart if running */
JOB_RESTART_FINISH, /* 2nd part of a restart, i.e. the actual starting */
_JOB_TYPE_MAX
};
typedef enum JobState {
JOB_WAITING,
JOB_RUNNING,
JOB_DONE,
_JOB_STATE_MAX
} JobState;
enum JobMode {
JOB_FAIL,
JOB_REPLACE,
_JOB_MODE_MAX
};
struct Job {
Manager *manager;
uint32_t id;
JobType type;
JobState state;
Name *name;
bool linked:1;
};
Job* job_new(Manager *m, JobType type, Name *name);
int job_link(Job *job);
void job_free(Job *job);
#endif
/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foolisthfoo
#define foolisthfoo
/* The head of the linked list. Use this in the structure that shall
* contain the head of the linked list */
#define LIST_HEAD(t,name) \
t *name
/* The pointers in the linked list's items. Use this in the item structure */
#define LIST_FIELDS(t) \
t *next, *prev
/* Initialize the list's head */
#define LIST_HEAD_INIT(t,item) \
do { \
(item) = (t*) NULL; } \
while(false)
/* Initialize a list item */
#define LIST_INIT(t,item) \
do { \
t *_item = (item); \
assert(_item); \
_item->prev = _item->next = NULL; \
} while(false)
/* Prepend an item to the list */
#define LIST_PREPEND(t,head,item) \
do { \
t **_head = &(head), *_item = (item); \
assert(_item); \
if ((_item->next = *_head)) \
_item->next->prev = _item; \
_item->prev = NULL; \
*_head = _item; \
} while(false)
/* Remove an item from the list */
#define LIST_REMOVE(t,head,item) \
do { \
t **_head = &(head), *_item = (item); \
assert(_item); \
if (_item->next) \
_item->next->prev = _item->prev; \
if (_item->prev) \
_item->prev->next = _item->next; \
else { \
assert(*_head == _item); \
*_head = _item->next; \
} \
_item->next = _item->prev = NULL; \
} while(false)
/* Find the head of the list */
#define LIST_FIND_HEAD(t,item,head) \
do { \
t **_head = (head), *_item = (item); \
*_head = _item; \
assert(_head); \
while ((*_head)->prev) \
*_head = (*_head)->prev; \
} while (false)
/* Insert an item after another one (a = where, b = what) */
#define LIST_INSERT_AFTER(t,head,a,b) \
do { \
t **_head = &(head), *_a = (a), *_b = (b); \
assert(_b); \
if (!_a) { \
if ((_b->next = *_head)) \
_b->next->prev = _b; \
_b->prev = NULL; \
*_head = _b; \
} else { \
if ((_b->next = _a->next)) \
_b->next->prev = _b; \
_b->prev = _a; \
_a->next = _b; \
} \
} while(false)
#define LIST_FOREACH(i,head) \
for (i = (head); i; i = i->next)
#define LIST_FOREACH_SAFE(i,n,head) \
for (i = (head); i && ((n = i->next), 1); i = n)
#endif
/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foomacrohfoo
#define foomacrohfoo
#include <assert.h>
#include <sys/types.h>
#define __printf_attr(a,b) __attribute__ ((format (printf, a, b)))
#define __sentinel __attribute__ ((sentinel))
#define __noreturn __attribute__((noreturn))
#define __unused __attribute__ ((unused))
#define __destructor __attribute__ ((destructor))
#define __pure __attribute__ ((pure))
#define __const __attribute__ ((const))
#define __deprecated __attribute__ ((deprecated))
#define __packed __attribute__ ((packed))
#define __malloc __attribute__ ((malloc))
/* Rounds up */
static inline size_t ALIGN(size_t l) {
return ((l + sizeof(void*) - 1) & ~(sizeof(void*) - 1));
}
#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
#define MAX(a,b) \
__extension__ ({ \
typeof(a) _a = (a); \
typeof(b) _b = (b); \