Page MenuHomeFreeBSD

kernel: Use the compiler supported constructor and destructor attributes to register sysinits.
Needs ReviewPublic

Authored by hselasky on Jun 7 2023, 12:35 PM.
Tags
None
Referenced Files
Unknown Object (File)
Wed, May 8, 9:12 PM
Unknown Object (File)
Mon, Apr 29, 7:54 AM
Unknown Object (File)
Sat, Apr 27, 9:18 PM
Unknown Object (File)
Sat, Apr 27, 9:18 AM
Unknown Object (File)
Tue, Apr 16, 3:50 AM
Unknown Object (File)
Apr 9 2024, 7:27 PM
Unknown Object (File)
Apr 7 2024, 2:21 AM
Unknown Object (File)
Apr 6 2024, 9:42 AM

Details

Reviewers
imp
kib
Summary

This change can also be seen as a step towards supporting more languages in the
kernel, requiring constructors as part of the language, for example C++.

All SYSINITs and SYSUNINITs are registered by a prioritized constructor.

By using a linked list no memory needs to be allocated to sort
the entries during early boot.

The register functions are simply caching the last entry added to the list,
to optimise sorted list insertion. Constructors are sorted by ascending priority
and destructors by descending priority.

The sysinit debugger command is now replaced by a constructors and
destructors command to show all constructors and destructors respectivly.

Sponsored by: NVIDIA Networking

Test Plan

There are some dependencies not provided.

This patch shows the main idea of the intended change.

This patch is take two on D40193 and D39916, and starts with D40450 .

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped

Event Timeline

Keep "struct __hack" to force semicolon after SYSINIT() and SYSUNINIT().

MFC after: 1 week

There is no way this can be MFC'ed, it is a big pile of KBI break.

Also, not all architectures use .ctors, some use .init_array, and modern compilers are migrating older architectures over to that too.

Finally, I'm highly unconvinced that it makes sense to dynamically register each sysinit individually. It wouldn't surprise me if building and using that linked list ends up being slower than just running qsort over an array on boot.

MFC after: 1 week

There is no way this can be MFC'ed, it is a big pile of KBI break.

Right, the MFC after followed my commit template. Now removed.

Also, not all architectures use .ctors, some use .init_array, and modern compilers are migrating older architectures over to that too.

If we need to check two sections or just one, isn't that just trivial? It works in user-space?

And if we need to support other kernel languages, this may be needed anyway.

Isn't it better to use established compiler features than custom sections/datasets?

Finally, I'm highly unconvinced that it makes sense to dynamically register each sysinit individually. It wouldn't surprise me if building and using that linked list ends up being slower than just running qsort over an array on boot.

Did you look at the priority argument for the constructors and destructors?

Did you notice the sysinit_insert_sorted() function keeps track of the last registered sysinit, so it doesn't have to traverse the full list to find the correct location. This should be way faster than any form of sorting!

And further down, we can factor out all the VNET sysinit's too.

Technically we don't need to map our subsystems and orders into 16-bits of priority, but we could simply hash the priorities we've got, to speedup the insertion process.

sys/sys/kernel.h
88–89

In this patch I've compressed the enum ranges, but it is not required, and I might revert that bit.

Finally, I'm highly unconvinced that it makes sense to dynamically register each sysinit individually.

How else can type-safety for the callback function's argument be achieved if you need to cast it to some const void * in struct sysinit ?

Yes, I read the code, thank you for asking

Change from .ctors to .init_array and .dtors to .fini_array . This is what the default FreeBSD kernel toolchain currently outputs. Also noted by @jrtc27 .

We might need to support both.

Oh also linker_file_lookup_set with a section name like that won't work on anything other than amd64, since link_elf relies on the start/stop symbols, not the section name.

Oh also linker_file_lookup_set with a section name like that won't work on anything other than amd64, since link_elf relies on the start/stop symbols, not the section name.

Please tell me if I'm mistaken, but isn't that all controlled by the ldscripts we have?

I'm just about to test D40467 on aarch64. It seems to do the trick, at least as seen by objdump.

Fix a bug in sysinit_insert_sorted().

Test results on aarch64 shows around 1800 constructors.

When using the full 16-bits of priority this results in:
sysinit_insert_sorted() looped 11236 times

When using only 257 priority levels this results in:
sysinit_insert_sorted() looped 26236 times

On average the insertion loop then needs to spin 14 times and that's pretty much OK, given the sysinit ordering can be kept AS-IS.

Oh also linker_file_lookup_set with a section name like that won't work on anything other than amd64, since link_elf relies on the start/stop symbols, not the section name.

Please tell me if I'm mistaken, but isn't that all controlled by the ldscripts we have?

I'm just about to test D40467 on aarch64. It seems to do the trick, at least as seen by objdump.

After my ldscript changes and looking at how libc is doing it, we can use the symbol lookup function to get the pointers to these arrays.

Change %03X to %07X to print subsystem values, now that I reverted the renumbering of the subsystem and order values.