Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F115929834
D40463.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
22 KB
Referenced Files
None
Subscribers
None
D40463.diff
View Options
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -140,66 +140,132 @@
* - 0, 'compiled in but silent by default'
* - 1, 'compiled in but verbose by default' (default)
*/
-int verbose_sysinit = VERBOSE_SYSINIT;
+static int verbose_sysinit = VERBOSE_SYSINIT;
TUNABLE_INT("debug.verbose_sysinit", &verbose_sysinit);
+SYSCTL_INT(_debug, OID_AUTO, verbose_sysinit, CTLFLAG_RDTUN | CTLFLAG_NOFETCH,
+ &verbose_sysinit, 0, "Verbose sysinit enabled, if non-zero");
#endif
#ifdef INVARIANTS
FEATURE(invariants, "Kernel compiled with INVARIANTS, may affect performance");
#endif
+extern sysinit_func_t * const __init_array_start[] __hidden;
+extern sysinit_func_t * const __init_array_end[] __hidden;
+extern sysinit_func_t * const __fini_array_start[] __hidden;
+extern sysinit_func_t * const __fini_array_end[] __hidden;
+
/*
- * This ensures that there is at least one entry so that the sysinit_set
- * symbol is not undefined. A sybsystem ID of SI_SUB_DUMMY is never
- * executed.
+ * Compare two sysinit structures.
*/
+static int
+sysinit_compare(const struct sysinit *pa, const struct sysinit *pb, int neg)
+{
+ if (pa->subsystem > pb->subsystem)
+ return (neg);
+ else if (pa->subsystem < pb->subsystem)
+ return (-neg);
+ else if (pa->order > pb->order)
+ return (neg);
+ else if (pa->order < pb->order)
+ return (-neg);
+ else
+ return (0);
+}
+
+SYSINIT_DECLARE_HEAD(sysinit_head);
+SYSINIT_DECLARE_HEAD(sysuninit_head);
+
+#ifdef VERBOSE_SYSINIT
+static size_t sysinit_insert_ops;
static void
-placeholder(void)
+sysinit_insert_ops_print(void)
{
+ if (bootverbose != 0 || verbose_sysinit != 0)
+ printf("sysinit_insert_sorted() looped %zu times\n", sysinit_insert_ops);
}
-SYSINIT(placeholder, SI_SUB_DUMMY, SI_ORDER_ANY, placeholder);
+SYSINIT(sysinit_insert_ops_print, SI_SUB_LAST, SI_ORDER_ANY, sysinit_insert_ops_print);
+#endif
/*
- * The sysinit table itself. Items are checked off as the are run.
- * If we want to register new sysinit types, add them to newsysinit.
+ * Insert a sysinit structure into a list sorted by subsystem and order.
+ *
+ * @param ptr Pointer to the sysinit structure to be inserted.
+ * @param phead Pointer to the head structure for the sysinits.
+ * @param neg 1: Ascending order -1: Descending order
*/
-SET_DECLARE(sysinit_set, struct sysinit);
-struct sysinit **sysinit, **sysinit_end;
-struct sysinit **newsysinit, **newsysinit_end;
+void
+sysinit_insert_sorted(struct sysinit *ptr, sysinit_head_t *phead, int neg)
+{
+ /* don't insert reserved entries */
+ if (ptr->subsystem == SI_SUB_DUMMY)
+ return;
+
+ if (TAILQ_FIRST(&phead->h) == NULL) {
+ TAILQ_INSERT_TAIL(&phead->h, ptr, entry);
+ } else {
+ for (;;) {
+ struct sysinit *pnext;
+ struct sysinit *pprev;
+ int cmp;
+
+ pnext = TAILQ_NEXT(phead->l, entry);
+ pprev = TAILQ_PREV(phead->l, __sysinit_head, entry);
+
+ cmp = sysinit_compare(ptr, phead->l, neg);
+ if (cmp < 0) {
+ /* go backwards in list */
+ if (pprev == NULL) {
+ TAILQ_INSERT_HEAD(&phead->h, ptr, entry);
+ break;
+ } else {
+ phead->l = pprev;
+ }
+ } else if (pnext == NULL || sysinit_compare(ptr, pnext, neg) < 0) {
+ /* insert after last element */
+ TAILQ_INSERT_AFTER(&phead->h, phead->l, ptr, entry);
+ break;
+ } else {
+ /* advance to next element */
+ phead->l = pnext;
+ }
+#ifdef VERBOSE_SYSINIT
+ sysinit_insert_ops++;
+#endif
+ }
+ }
+ phead->l = ptr;
+}
/*
- * Merge a new sysinit set into the current set, reallocating it if
- * necessary. This can only be called after malloc is running.
+ * Remove a sysinit structure from a list.
+
+ * @param ptr Pointer to the sysinit structure to be removed
+ * @param phead Pointer to the head structure for the sysinits
*/
void
-sysinit_add(struct sysinit **set, struct sysinit **set_end)
+sysinit_remove(struct sysinit *ptr, sysinit_head_t *phead)
{
- struct sysinit **newset;
- struct sysinit **sipp;
- struct sysinit **xipp;
- int count;
-
- count = set_end - set;
- if (newsysinit)
- count += newsysinit_end - newsysinit;
- else
- count += sysinit_end - sysinit;
- newset = malloc(count * sizeof(*sipp), M_TEMP, M_NOWAIT);
- if (newset == NULL)
- panic("cannot malloc for sysinit");
- xipp = newset;
- if (newsysinit)
- for (sipp = newsysinit; sipp < newsysinit_end; sipp++)
- *xipp++ = *sipp;
- else
- for (sipp = sysinit; sipp < sysinit_end; sipp++)
- *xipp++ = *sipp;
- for (sipp = set; sipp < set_end; sipp++)
- *xipp++ = *sipp;
- if (newsysinit)
- free(newsysinit, M_TEMP);
- newsysinit = newset;
- newsysinit_end = newset + count;
+ /* update last pointer to next element, if it was removed */
+ if (phead->l == ptr) {
+ phead->l = TAILQ_NEXT(ptr, entry);
+ /* if cannot go forward, then go backwards */
+ if (phead->l == NULL)
+ phead->l = TAILQ_PREV(ptr, __sysinit_head, entry);
+ }
+ TAILQ_REMOVE(&phead->h, ptr, entry);
+}
+
+void
+sysinit_constructor_register(struct sysinit *ptr)
+{
+ sysinit_insert_sorted(ptr, &sysinit_head, 1);
+}
+
+void
+sysinit_destructor_register(struct sysinit *ptr)
+{
+ sysinit_insert_sorted(ptr, &sysuninit_head, -1);
}
#if defined (DDB) && defined(VERBOSE_SYSINIT)
@@ -220,6 +286,53 @@
}
#endif
+void
+sysinit_execute(sysinit_head_t *phead, const char *fname)
+{
+ struct sysinit *ptr;
+ enum sysinit_sub_id last = SI_SUB_DUMMY;
+#if defined(VERBOSE_SYSINIT)
+ bool verbose = false;
+#endif
+
+ while ((ptr = TAILQ_FIRST(&phead->h))) {
+ sysinit_remove(ptr, phead);
+
+ if (last != ptr->subsystem) {
+ last = ptr->subsystem;
+ BOOTTRACE("%s: sysinit execute 0x%07X", fname, last);
+
+#if defined(VERBOSE_SYSINIT)
+ verbose = last > SI_SUB_COPYRIGHT && verbose_sysinit != 0;
+ if (verbose)
+ printf("subsystem 0x%07X\n", last);
+#endif
+ }
+
+#if defined(VERBOSE_SYSINIT)
+ if (verbose) {
+#if defined(DDB)
+ const char *func;
+
+ func = symbol_name((vm_offset_t)ptr->func,
+ DB_STGY_PROC);
+ if (func != NULL)
+ printf(" %s()... ", func);
+ else
+#endif
+ printf(" %p()... ", ptr->func);
+ }
+#endif
+ /* execute sysinit */
+ ptr->func();
+
+#if defined(VERBOSE_SYSINIT)
+ if (verbose)
+ printf("done.\n");
+#endif
+ }
+}
+
/*
* System startup; initialize the world, create process 0, mount root
* filesystem, and fork to create init and pagedaemon. Most of the
@@ -234,115 +347,36 @@
void
mi_startup(void)
{
-
- struct sysinit **sipp; /* system initialization*/
- struct sysinit **xipp; /* interior loop of sort*/
- struct sysinit *save; /* bubble*/
-
- int last;
-#if defined(VERBOSE_SYSINIT)
- int verbose;
-#endif
+ sysinit_func_t * const * si_start;
+ sysinit_func_t * const * si_stop;
TSENTER();
if (boothowto & RB_VERBOSE)
bootverbose++;
- if (sysinit == NULL) {
- sysinit = SET_BEGIN(sysinit_set);
- sysinit_end = SET_LIMIT(sysinit_set);
- }
-
-restart:
- /*
- * Perform a bubble sort of the system initialization objects by
- * their subsystem (primary key) and order (secondary key).
- */
- TSENTER2("bubblesort");
- for (sipp = sysinit; sipp < sysinit_end; sipp++) {
- for (xipp = sipp + 1; xipp < sysinit_end; xipp++) {
- if ((*sipp)->subsystem < (*xipp)->subsystem ||
- ((*sipp)->subsystem == (*xipp)->subsystem &&
- (*sipp)->order <= (*xipp)->order))
- continue; /* skip*/
- save = *sipp;
- *sipp = *xipp;
- *xipp = save;
- }
- }
- TSEXIT2("bubblesort");
+ si_start = __init_array_start;
+ si_stop = __init_array_end;
- last = SI_SUB_COPYRIGHT;
-#if defined(VERBOSE_SYSINIT)
- verbose = 0;
-#if !defined(DDB)
+#if defined(VERBOSE_SYSINIT) && !defined(DDB)
printf("VERBOSE_SYSINIT: DDB not enabled, symbol lookups disabled.\n");
#endif
-#endif
-
- /*
- * Traverse the (now) ordered list of system initialization tasks.
- * Perform each task, and continue on to the next task.
- */
- for (sipp = sysinit; sipp < sysinit_end; sipp++) {
- if ((*sipp)->subsystem == SI_SUB_DUMMY)
- continue; /* skip dummy task(s)*/
-
- if ((*sipp)->subsystem == SI_SUB_DONE)
- continue;
-
- if ((*sipp)->subsystem > last)
- BOOTTRACE_INIT("sysinit 0x%7x", (*sipp)->subsystem);
+ /* run all the kernel constructors */
+ for (; si_start != si_stop; si_start++) {
#if defined(VERBOSE_SYSINIT)
- if ((*sipp)->subsystem > last && verbose_sysinit != 0) {
- verbose = 1;
- printf("subsystem %x\n", last);
+ if (bootverbose != 0) {
+ printf("Constructor[%zu/%zu]=%p\n",
+ (size_t)(si_start - __init_array_start),
+ (size_t)(si_stop - __init_array_start - 1), *si_start);
}
- if (verbose) {
-#if defined(DDB)
- const char *func, *data;
-
- func = symbol_name((vm_offset_t)(*sipp)->func,
- DB_STGY_PROC);
- data = symbol_name((vm_offset_t)(*sipp)->udata,
- DB_STGY_ANY);
- if (func != NULL && data != NULL)
- printf(" %s(&%s)... ", func, data);
- else if (func != NULL)
- printf(" %s(%p)... ", func, (*sipp)->udata);
- else
-#endif
- printf(" %p(%p)... ", (*sipp)->func,
- (*sipp)->udata);
- }
-#endif
-
- /* Call function */
- (*((*sipp)->func))((*sipp)->udata);
-
-#if defined(VERBOSE_SYSINIT)
- if (verbose)
- printf("done.\n");
#endif
-
- /* Check off the one we're just done */
- last = (*sipp)->subsystem;
- (*sipp)->subsystem = SI_SUB_DONE;
-
- /* Check if we've installed more sysinit items via KLD */
- if (newsysinit != NULL) {
- if (sysinit != SET_BEGIN(sysinit_set))
- free(sysinit, M_TEMP);
- sysinit = newsysinit;
- sysinit_end = newsysinit_end;
- newsysinit = NULL;
- newsysinit_end = NULL;
- goto restart;
- }
+ (*si_start)();
}
+ /* execute all the sysinits */
+ sysinit_execute(&sysinit_head, "kernel");
+
TSEXIT(); /* Here so we don't overlap with start_init. */
BOOTTRACE("mi_startup done");
@@ -871,9 +905,9 @@
*/
#ifdef DDB
static void
-db_show_print_syinit(struct sysinit *sip, bool ddb)
+db_show_print_function(sysinit_func_t *func, bool ddb)
{
- const char *sname, *funcname;
+ const char *funcname;
c_db_sym_t sym;
db_expr_t offset;
@@ -883,31 +917,44 @@
else \
printf(__VA_ARGS__)
- if (sip == NULL) {
- xprint("%s: no sysinit * given\n", __func__);
+ if (func == NULL) {
+ xprint("%s: no function given\n", __func__);
return;
}
- sym = db_search_symbol((vm_offset_t)sip, DB_STGY_ANY, &offset);
- db_symbol_values(sym, &sname, NULL);
- sym = db_search_symbol((vm_offset_t)sip->func, DB_STGY_PROC, &offset);
+ sym = db_search_symbol((vm_offset_t)func, DB_STGY_PROC, &offset);
db_symbol_values(sym, &funcname, NULL);
- xprint("%s(%p)\n", (sname != NULL) ? sname : "", sip);
- xprint(" %#08x %#08x\n", sip->subsystem, sip->order);
- xprint(" %p(%s)(%p)\n",
- sip->func, (funcname != NULL) ? funcname : "", sip->udata);
+ xprint("%s(%p)\n", funcname, func);
#undef xprint
}
-DB_SHOW_COMMAND_FLAGS(sysinit, db_show_sysinit, DB_CMD_MEMSAFE)
+DB_SHOW_COMMAND_FLAGS(constructors, db_show_constructors, DB_CMD_MEMSAFE)
+{
+ sysinit_func_t * const * si_start;
+ sysinit_func_t * const * si_stop;
+
+ si_start = __init_array_start;
+ si_stop = __init_array_end;
+
+ db_printf("CONSTRUCTORS vs Name(Ptr)\n");
+ for (; si_start != si_stop; si_start++) {
+ db_show_print_function(*si_start, true);
+ if (db_pager_quit)
+ break;
+ }
+}
+
+DB_SHOW_COMMAND_FLAGS(destructors, db_show_destructors, DB_CMD_MEMSAFE)
{
- struct sysinit **sipp;
+ sysinit_func_t * const * si_start;
+ sysinit_func_t * const * si_stop;
+
+ si_start = __fini_array_start;
+ si_stop = __fini_array_end;
- db_printf("SYSINIT vs Name(Ptr)\n");
- db_printf(" Subsystem Order\n");
- db_printf(" Function(Name)(Arg)\n");
- for (sipp = sysinit; sipp < sysinit_end; sipp++) {
- db_show_print_syinit(*sipp, true);
+ db_printf("DESTRUCTORS vs Name(Ptr)\n");
+ for (; si_start != si_stop; si_start++) {
+ db_show_print_function(*si_start, true);
if (db_pager_quit)
break;
}
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -135,6 +135,14 @@
(a) = next_file_id; \
} while (0)
+#define LINKER_LOOKUP_ARRAY(file,name,start,stop) ({ \
+ start = (sysinit_func_t * const *) \
+ linker_file_lookup_symbol_internal(file, #name "_start", 0);\
+ stop = (sysinit_func_t * const *) \
+ linker_file_lookup_symbol_internal(file, #name "_end", 0); \
+ (start) != NULL && (stop) != NULL; \
+})
+
/* XXX wrong name; we're looking at version provision tags here, not modules */
typedef TAILQ_HEAD(, modlist) modlisthead_t;
struct modlist {
@@ -195,54 +203,27 @@
static void
linker_file_sysinit(linker_file_t lf)
{
- struct sysinit **start, **stop, **sipp, **xipp, *save;
- int last;
+ sysinit_func_t * const * si_start;
+ sysinit_func_t * const * si_stop;
- KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n",
+ KLD_DPF(FILE, ("linker_file_sysinit: calling constructors for %s\n",
lf->filename));
sx_assert(&kld_sx, SA_XLOCKED);
- if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0)
+ if (LINKER_LOOKUP_ARRAY(lf, __init_array, si_start, si_stop) == false)
return;
- /*
- * Perform a bubble sort of the system initialization objects by
- * their subsystem (primary key) and order (secondary key).
- *
- * Since some things care about execution order, this is the operation
- * which ensures continued function.
- */
- for (sipp = start; sipp < stop; sipp++) {
- for (xipp = sipp + 1; xipp < stop; xipp++) {
- if ((*sipp)->subsystem < (*xipp)->subsystem ||
- ((*sipp)->subsystem == (*xipp)->subsystem &&
- (*sipp)->order <= (*xipp)->order))
- continue; /* skip */
- save = *sipp;
- *sipp = *xipp;
- *xipp = save;
- }
- }
- /*
- * Traverse the (now) ordered list of system initialization tasks.
- * Perform each task, and continue on to the next task.
- */
- last = SI_SUB_DUMMY;
sx_xunlock(&kld_sx);
mtx_lock(&Giant);
- for (sipp = start; sipp < stop; sipp++) {
- if ((*sipp)->subsystem == SI_SUB_DUMMY)
- continue; /* skip dummy task(s) */
- if ((*sipp)->subsystem > last)
- BOOTTRACE("%s: sysinit 0x%7x", lf->filename,
- (*sipp)->subsystem);
+ /* run all the constructors provided by the kernel module */
+ for (; si_start != si_stop; si_start++)
+ (*si_start)();
+
+ /* run all the registered SYSINITs */
+ sysinit_execute(&sysinit_head, lf->filename);
- /* Call function */
- (*((*sipp)->func)) ((*sipp)->udata);
- last = (*sipp)->subsystem;
- }
mtx_unlock(&Giant);
sx_xlock(&kld_sx);
}
@@ -250,56 +231,27 @@
static void
linker_file_sysuninit(linker_file_t lf)
{
- struct sysinit **start, **stop, **sipp, **xipp, *save;
- int last;
+ sysinit_func_t * const * si_start;
+ sysinit_func_t * const * si_stop;
- KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n",
+ KLD_DPF(FILE, ("linker_file_sysuninit: calling destructors for %s\n",
lf->filename));
sx_assert(&kld_sx, SA_XLOCKED);
- if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop,
- NULL) != 0)
+ if (LINKER_LOOKUP_ARRAY(lf, __fini_array, si_start, si_stop) == false)
return;
- /*
- * Perform a reverse bubble sort of the system initialization objects
- * by their subsystem (primary key) and order (secondary key).
- *
- * Since some things care about execution order, this is the operation
- * which ensures continued function.
- */
- for (sipp = start; sipp < stop; sipp++) {
- for (xipp = sipp + 1; xipp < stop; xipp++) {
- if ((*sipp)->subsystem > (*xipp)->subsystem ||
- ((*sipp)->subsystem == (*xipp)->subsystem &&
- (*sipp)->order >= (*xipp)->order))
- continue; /* skip */
- save = *sipp;
- *sipp = *xipp;
- *xipp = save;
- }
- }
-
- /*
- * Traverse the (now) ordered list of system initialization tasks.
- * Perform each task, and continue on to the next task.
- */
sx_xunlock(&kld_sx);
mtx_lock(&Giant);
- last = SI_SUB_DUMMY;
- for (sipp = start; sipp < stop; sipp++) {
- if ((*sipp)->subsystem == SI_SUB_DUMMY)
- continue; /* skip dummy task(s) */
-
- if ((*sipp)->subsystem > last)
- BOOTTRACE("%s: sysuninit 0x%7x", lf->filename,
- (*sipp)->subsystem);
-
- /* Call function */
- (*((*sipp)->func)) ((*sipp)->udata);
- last = (*sipp)->subsystem;
- }
+
+ /* run all the destructors provided by the kernel module */
+ for (; si_start != si_stop; si_start++)
+ (*si_start)();
+
+ /* run all the registered SYSUNINITs */
+ sysinit_execute(&sysuninit_head, lf->filename);
+
mtx_unlock(&Giant);
sx_xlock(&kld_sx);
}
@@ -1581,7 +1533,8 @@
int nver;
int resolves;
modlist_t mod;
- struct sysinit **si_start, **si_stop;
+ sysinit_func_t * const * si_start;
+ sysinit_func_t * const * si_stop;
TAILQ_INIT(&loaded_files);
TAILQ_INIT(&depended_files);
@@ -1762,9 +1715,10 @@
linker_file_register_modules(lf);
if (!TAILQ_EMPTY(&lf->modules))
lf->flags |= LINKER_FILE_MODULES;
- if (linker_file_lookup_set(lf, "sysinit_set", &si_start,
- &si_stop, NULL) == 0)
- sysinit_add(si_start, si_stop);
+ if (LINKER_LOOKUP_ARRAY(lf, __init_array, si_start, si_stop)) {
+ for (; si_start != si_stop; si_start++)
+ (*si_start)();
+ }
linker_file_register_sysctls(lf, true);
lf->flags |= LINKER_FILE_LINKED;
continue;
diff --git a/sys/net/vnet.h b/sys/net/vnet.h
--- a/sys/net/vnet.h
+++ b/sys/net/vnet.h
@@ -320,6 +320,8 @@
*/
#include <sys/kernel.h>
+typedef void (*sysinit_cfunc_t)(const void *);
+
/*
* SYSINIT/SYSUNINIT variants that provide per-vnet constructors and
* destructors.
diff --git a/sys/sys/kernel.h b/sys/sys/kernel.h
--- a/sys/sys/kernel.h
+++ b/sys/sys/kernel.h
@@ -49,11 +49,10 @@
#include <sys/linker_set.h>
-#ifdef _KERNEL
-
-/* for intrhook below */
#include <sys/queue.h>
+#ifdef _KERNEL
+
/* for timestamping SYSINITs; other files may assume this is included here */
#include <sys/tslog.h>
@@ -88,7 +87,6 @@
*/
enum sysinit_sub_id {
SI_SUB_DUMMY = 0x0000000, /* not executed; for linker*/
- SI_SUB_DONE = 0x0000001, /* processed*/
SI_SUB_TUNABLES = 0x0700000, /* establish tunable values */
SI_SUB_COPYRIGHT = 0x0800001, /* first use of console*/
SI_SUB_VM = 0x1000000, /* virtual memory system init */
@@ -192,37 +190,30 @@
SI_ORDER_ANY = 0xfffffff /* last*/
};
-/*
- * A system initialization call instance
- *
- * At the moment there is one instance of sysinit. We probably do not
- * want two which is why this code is if'd out, but we definitely want
- * to discern SYSINIT's which take non-constant data pointers and
- * SYSINIT's which take constant data pointers,
- *
- * The C_* macros take functions expecting const void * arguments
- * while the non-C_* macros take functions expecting just void * arguments.
- *
- * With -Wcast-qual on, the compiler issues warnings:
- * - if we pass non-const data or functions taking non-const data
- * to a C_* macro.
- *
- * - if we pass const data to the normal macros
- *
- * However, no warning is issued if we pass a function taking const data
- * through a normal non-const macro. This is ok because the function is
- * saying it won't modify the data so we don't care whether the data is
- * modifiable or not.
- */
+struct sysinit;
+
+TAILQ_HEAD(__sysinit_head, sysinit);
+
+typedef struct {
+ struct __sysinit_head h;
+ struct sysinit *l; /* last entry added - to optimise sorted insertion */
+} sysinit_head_t;
+
+#define SYSINIT_DECLARE_HEAD(name) \
+ sysinit_head_t name = { .h = TAILQ_HEAD_INITIALIZER(name.h), .l = NULL }
+
+#define SYSINIT_FOREACH(ptr, head) \
+ TAILQ_FOREACH(ptr, &(head)->h, entry)
-typedef void (*sysinit_nfunc_t)(void *);
-typedef void (*sysinit_cfunc_t)(const void *);
+typedef TAILQ_ENTRY(sysinit) sysinit_entry_t;
+
+typedef void (sysinit_func_t)(void);
struct sysinit {
- enum sysinit_sub_id subsystem; /* subsystem identifier*/
- enum sysinit_elem_order order; /* init order within subsystem*/
- sysinit_cfunc_t func; /* function */
- const void *udata; /* multiplexer/argument */
+ sysinit_entry_t entry; /* entry for list */
+ sysinit_func_t *func; /* function pointer */
+ enum sysinit_sub_id subsystem; /* subsystem identifier */
+ enum sysinit_elem_order order; /* init order within subsystem */
};
/*
@@ -243,11 +234,18 @@
do { } while (0)
#endif
+#define __SI_PRIORITY_START 100
+#define __SI_PRIORITY_NUM 257 /* should be a prime number */
+
+#define __SI_PRIORITY_HASH(sub, order) \
+ (((sub) % __SI_PRIORITY_NUM) + \
+ ((order) % __SI_PRIORITY_NUM) + __SI_PRIORITY_START)
+
/*
* Explanation of arguments for the __SI_REGISTER() macro:
*
* @param uniq An identifier for the needed functions and structures.
- * @param type sysinit_set or sysuninit_set, depending on use case.
+ * @param type constructor or destructor, depending on use case.
* @param _sub SI_SUB_XXX enum.
* @param _order SI_ORDER_XXX enum.
* @param _func Pointer to callback function.
@@ -259,37 +257,49 @@
* pointer casting between types is avoided entirely.
*/
#define __SI_REGISTER(uniq, type, _sub, _order, _func, ...) \
+_Static_assert((_sub) > SI_SUB_DUMMY && (_sub) <= SI_SUB_LAST, \
+ "Subsystem is out of range"); \
+_Static_assert((_order) >= 0 && (_order) <= SI_ORDER_ANY, \
+ "Order is out of range"); \
static void \
-type##_##uniq##_shim(const void *arg __unused) \
+type##_##uniq##_shim(void) \
{ \
__SI_FUNCTION_PRE(type, _func); \
(_func)(__VA_ARGS__); \
__SI_FUNCTION_POST(type, _func); \
} \
-static struct sysinit type##_##uniq = { \
- .subsystem = _sub, \
- .order = _order, \
- .func = &type##_##uniq##_shim, \
- .udata = NULL, \
-}; \
-DATA_WSET(type, type##_##uniq); \
+static void __attribute__((type(__SI_PRIORITY_HASH(_sub, _order)))) \
+ type##_##uniq##_register(void) { \
+ static struct sysinit __data = { \
+ .subsystem = _sub, \
+ .order = _order, \
+ .func = &type##_##uniq##_shim, \
+ }; \
+ sysinit_##type##_register(&__data); \
+} \
struct __hack
/*
* Sysinit API macro, called on kernel or module load:
*/
#define SYSINIT(uniq, sub, order, ...) \
- __SI_REGISTER(uniq, sysinit_set, sub, order, __VA_ARGS__)
+ __SI_REGISTER(uniq, constructor, sub, order, __VA_ARGS__)
/*
* Sysuninit API macros, called on module unload:
*/
#define SYSUNINIT(uniq, sub, order, ...) \
- __SI_REGISTER(uniq, sysuinit_set, sub, order, __VA_ARGS__)
-
-void sysinit_add(struct sysinit **set, struct sysinit **set_end);
+ __SI_REGISTER(uniq, destructor, sub, order, __VA_ARGS__)
#ifdef _KERNEL
+extern sysinit_head_t sysinit_head;
+extern sysinit_head_t sysuninit_head;
+
+void sysinit_insert_sorted(struct sysinit *, sysinit_head_t *, int neg);
+void sysinit_remove(struct sysinit *, sysinit_head_t *);
+void sysinit_constructor_register(struct sysinit *);
+void sysinit_destructor_register(struct sysinit *);
+void sysinit_execute(sysinit_head_t *, const char *);
/*
* Infrastructure for tunable 'constants'. Value may be specified at compile
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, May 1, 1:20 PM (8 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17882447
Default Alt Text
D40463.diff (22 KB)
Attached To
Mode
D40463: kernel: Use the compiler supported constructor and destructor attributes to register sysinits.
Attached
Detach File
Event Timeline
Log In to Comment