#Zag
1 messages ยท Page 8 of 1
ah neat
the way freebsd does it is kinda crazy, historically sysctl didn't have names but rather IDs (so like kern.whatever would be something like [1, 2]), now it uses string names but to handle legacy code it still uses numerical IDs, and to find names it searches into a special ID
so you have to do 2 syscalls for sysctl, one to get the IDs from the string name and one to set the value
and it's a linear search of names in that entry ๐
what I do is have an AVL tree ordered by lexicographical ordering of the names in each directory, and the linux subsystem will simply convert file paths to the standard . syntax I guess
consider: std.StaticStringMap
if everything is defined statically anyway
idk how that would work
oh right tree not strict map
no it would work
but idk how to write it
because the way I do things rn parent is a type so I can't insert to it directly, I put nodes into an executable section and traverse it and insert them:
ah I don't think StaticStringMap would work here because I need to add the KVs one by one basically
you could somehow build it all at comptime? idk
there is probably a way to build the tree at comptime though
yeah, I just don't know how
do you think I can declare the type with const first then refer to the storage and add it to a comptime hashmap or something
like
const Holder = struct { var storage = ...};
comptime_hashmap.insert(&name, &holder.storage);
ah
im sure I could build it at compile time
it's just very annoying
yeah
I wish zig had some type of compile-time section or something, where you could iterate over all variables in that section and do stuff on them
Kind of a crazy concept but I think it'd be useful
@languid canyon what is that linux thing where you have variables that are read-only after boot
What are you asking exactly
Just a section thats changed to ro after init
__ro_after_boot I think
I've added tunables, which are cmdline parameters but better:
for dynamic parameters you might wanna set on boot
i saw it in xnu code and thought it was kinda like sysctl but it wasn't, though I will continue my sysctl-like thing too
this looks like linux' sysctls
like the way they're defined
I mean the syntax is similar but it's not really related, sysctl will be another layer on top of that for stuff that can be changed at runtime
i only meant syntax lol idk if they're related
this is my sysctl-like thing
I wont name it tunable tho I'll have to find another name
@heavy sandal LOL
lmao what did you do
self.cpus = @ptrCast(@alignCast(cpu_zone.alloc(.{}) catch @panic("Failed to allocate per-CPU magazine state")));
``` I think it doesnt like this
well I do pretty weird stuff
this is a []rtl.CachePadded(Cpu) type so it may not like this
since it's like an inline type or whatever
idk i do shit like that fairly often
only way to really be sure is to run a releasesafe or debug build of the compiler tho
and that takes like five years to build
what's funny is that this is 0.16 too
@crimson sand the NT functions for the memory thresholds are MiInitializeWorkingSetManagerParameters and MiUpdatePageThresholdsDpc
fkgjfkgj
perkenrle time
prekernel will do a bunch of stuff: detect cpuid, start APs, map kernel and pfndb
infy about to roast me
Why start aps in the prekernel? You will have to restart them for hotplug or resume from suspend anyway in the kernel
yeah ik, but I want the kernel to boot in a nice cozy environment
where all APs are spinning in their idle thread already
Ig if you decide to never support those features then its fine
i have to have duplicated code for pagemaps anyway so ๐คทโโ๏ธ
nah I do want to eventually
but like
it's duplicated code
not that bad
btw how does hotplug work, is it through ACPI?
Yeah, firmware notification on the cpu object in aml
i could always somehow have the same assembly file for the prekernel and kernel
like I don't really think it's a big issue
same thing for pagemaps, i have to have duplicated code kinda
I mean sure
see, in C I would share the headers
but I can't here

idk maybe I can but too much work
btw @solid marsh for hot(un)plug how do you protect for_each_online_cpu?
do you have a lock around the cpu count or something?
or is it atomic and it'll get picked up next time
i haven't implemented that yet
i thought of avoiding the lock by allocating all the cpu structures at startup
ig a lock would work but it'd be shitty
cuz when a cpu goes offline you wanna wait till everyone is out of these loops
and then those structures have a flag indicating whether they're online
so for each online cpu you're interested in, you can check the bitmap and the structure
you could probably do it through some kind of RCU thing
you avoid having a global lock, and if you set up transitivity well you only need the lock in the structure
yeah, I thought about that too
but I'll have to see how well it plays with hotplug
i do think acpi is guaranteed to have an object for each possible cpu/slot iirc so at least you dont have to allocate new for a hotplugged cpu
you wait till all cpus are in a quiescent state and decrease the CPU count only then
it'd be annoying because you'd have to park the cpus for a while until everyone is quiescent
but I don't think you really have a choice with unplug anyway
@heavy sandal how would you do this
or some kind of IPI actually
no that wouldn't work nvm
so i can think of two ways and one is way more fucked up than the other but both kinda suck
for hotunplugging cpus I'll have a percpu task which manages exactly this
option a is to use externs/exports and have the kernel link to the prekernel for shared stuff. downside is you lose access to zig slices, error unions, and generally anything that isnt extern
option b is you compile the prekernel and kernel as a single executable and then split the prekernel out using objcopy somehow
option c is you just @import the same file from both and live with the code being duplicated in memory - this is what i do for my bootloader protocol file by having the root files for the kernel and loader be one directory level lower than they arguably should
why would you need a cpu count? except for informative purposes
Idk how do you do for each cpu
What I do is do a for loop from 0 to ncpus
yeah, but ncpus stays constant
no
I have a compile time ncpus like Linux
And a runtime ncpus
Compile time is for max CPUs
what is the datastructure you traverse with the loop?
just loop every possible cpu and skip the thing if the cpu isnt present no?
This is convenient because zig has no macros and it would suck to do it through an iterator everytime
True but boring
Depends, but this is a fairly common thing
the compile time constant is the maximum amount of cpus the kernel can handle
And annoying
acpi will tell you what possible cpus there are so its not like youre looping to max cpus
then depending on the system the maximum amount of cpus is <= that
Yeah but then I have to not forget to do that
Unless I make it an iterator
Yeah that's what I do
But I have a runtime ncpus
and you say that it can vary during runtime?
uh
i don't understand why you would want that
yeah i dont understand either
like, let's go back to the bitmap example
what if you have cpus 0..49 and remove cpu number 21
ncpus=49, okay
how does this help you
Well if CPUs were unplugged yea
If the machine has 4 CPUs I can just do for (0..4) to go through every cpu
compile time ncpus is for cpumask
yes
just put all the possible cpus in a slice and skip not present ones imo, i dont see whats the problem about it especially if you either make an iterator or a helper for it
what sucks about them?
also this would require to allocate it no?
clunky to use
yes but only once because you get the slots ahead of time
idk why runtime ncpus doesnt work then
it's literally just the same thing
but you add if (!online(i)) continue
how so? ive never found
while(it.next()) |item| {}
to be clunky
yeah this is literally what im suggesting
what we are trying to say is that the number is useless, unless in your datastructure you remove offline cpus from being able to be iterated over
then that number is obviously needed
yes
I also use it for my counters that must go through every cpu
you dont need the number of active ones though because of the basic if(!online) continue
unless we've been spending who knows how long using different mental definitions of what ncpus refers to and not realised
i understand his definition of ncpus as "amount of cpus online"
yeah same
yeah
and thats the one i dont see a use for
so if you have 4 possible cores and 2 are online, ncpus=2
which is why it can vary
^
i dont see how that helps if its easier and way less sync required to just iterate possible cpus and skip offline ones
how do you iterate over online CPUs then? you iterate over the bitmap?
well the bitmap has the same issue then
or over a generic list of possible ones and skip offline
or also that
that would be slow if your CONFIG_NCPUS is high
i think that you rarely have to do such iteration
how do you protect races in the bitmap?
i have a few
no because you get a system-local max during init from acpi
one of the few cases I can think of right now is for picking on which cpu a task should be assigned on creation or when its affinity is changed
separate from your os's supported max
even in virtual machines?
also where is that
the madt will have entries for all possible cpus?
yes
yeah the madt cpu entries (also the cpu device/processor objects) will have status flags for not-present cpus
the only weird thing about the madt in x86 is that, well
there's 2 bits: enabled, and online capable
the spec says that entries where enabled and online capable are 0 must be ignored
ah it's the first bit
so enabled means "i am running from boot", and online capable means "i am a hotplug CPU"
only problem is, no one fucking SETS the second bit
also I use it e.g in the allocator to allocate per-cpu state
not even when there are real hotplug cpus
so you will have to find the processor objects
madt is fixed, you use the namespace objects for changeable ones
so in most computers, if you have both flags 0, the madt entry is just for padding
and in virtual machines (one of the very few places you'll find hotplug cpus), it may be hotpluggable
if the madt has both bits 0 then the cpu isnt plugged in or its padding
very helpful
the spec says that if both are 0 it should be ignored
well, must I think
so i have no idea why no one sets the online capable bit lmao
yes
a little bit
if you see the dmesg of a machine with padding entries, it will report as present even the padding cpus
and then trim them off
ig what i could do is make the for_each_online_cpu use the cpumask with only the online cpu bits set
so that way I dont have to figure out the number of possible cpus
yeah maybe I just dont support cpu hotplug 
only hotunplug ig
i think this is what linux does btw but idk the details offhand so i may be completely wrong
also static version for comptime length
that is what linux does
makes sense
so, apparently, from ACPI 6.3, the online capable bit is implemented, so if your tables are at that revision or greater, you can use that bit to know whether your cpu is usable (hotpluggable)
otherwise, if the enable bit is not set, for real hw is padding, and if in qemu, it's a hotplug cpu
@languid canyon insanity
idk how they protect against racy mask updates tho
there's a cpu write lock
they don't take it in the iterator tho
yeah, because you dont update in the iterator 
no but
in parallel there's a cpu starting
like, one CPU is doing a for_each_online_cpu and another is starting a new cpu
or worse, one CPU is doing a for_each_online_cpu and another is removing a CPU
you then have a lock outside that protecting
Yeah thats how thats set up, I have the 6.3 check in my kernel
nice
can i hire one of you two to do hardware/firmware bullshit
so i can do actually interesting stuff

how much $$$ are we talking about 
you will get 10 million$ in zagcoin
well, as i say
to me that doesnt sound really good, unless it's RW lock or something?
it is not that common to have to iterate over all online cpus
Well it says read lock right there so probably 
ig they could use a seqlock actually
and if you still really really want to remove the lock
i wonder
you could have an enable bit in the cpu structure too
so that enabled bit in cpu -> enabled bit in bitmap
Imo its not needed, you hotplug extremely rarely, so 99.9% of the time u grab the fast path read lock
well actually, if you decide to duplicate the bit then you 100% also want a lock in the cpu structure
so at this point better be linux and use a rwlock 
Could it?
why not
Seqlock allows intentional races, here you would be accessing freed data or trying to talk to a cpu thats been offlined before the second checkpoint
You really wanna block offlining while iterating this stuff
Like the nice thing is the way offlining is designed is the kernel only gets a request, but it decides exactly when ejection happens so you can postpone it until the lock is free
sorry i hadn't read this yet, I was planning on doing c) but I wonder if I import a kernel module would it also import all the stuff it imports?
or since zig is lazy it'll see those symbols are unused
yeah that's what I said earlier
you have to have a lock somehow to avoid the cpu state being iterated on
fucking hell i have so much stuff to do and I am so slow
if i worked full time on it im sure it'd still take like 1 year to get where i want
yeah i think so lol
I'd rather not rely on std anyway
ugly function names
(/s but mostly because it's not stable and there are no docs)
ime it will just be lazy
thats your decision lol
Nah I use it here and there it's just that particular thing I didn't know it had
I guess its useful but I reimplemented it anyway
How do you know the std so much
when i need a data structure i go looking in std first
this one in particular i use a lot though so i know it from that
but also just idk this is the sort of thing im good at learning and absorbing
like i still know half of the nonsense obscure things from the dotnet standard libraries despite not having used most of them
like my beloved conditionalweaktable
ive still never used it but i sure do know it
I'm thinking I can move all large pages to the loader
i mean handling of them
that'll simplify the kernel pmap code
@heavy sandal is there some kind of zig allocator i can just give a page alloc function to and it'll work
ideally id use arena allocator but i need another allocator for that
ah i think i can just use arena allocator with a custom page allocator my bad
i think
idk
debugallocator
which I think is getting renamed to safeallocator? idk
it also needs a mutex type iirc and is a bit slow tho
because it traces everything and does leak checks and all sorts of stuff like that
Hey @vital summit is the initgraph stuff fully compile time or are there steps that are added dynamically? Like if you detect some device of some sort do you add that step to the initgraph or do you run the init manually in one of the steps
If so how does that work? Initgraph steps can add other steps?
ah ig you register the tasks but u just dont do anything
all steps are static, but i have considered something like "don't init anything acpi if no rsdp"
cuz I'm sure I can cook something up with zig comptime and do it all at compile time
but if steps are added dynamically then not really
mhm ig u can have some kind of "features" attribute to init steps
and like if features has acpi and no acpi: dont run it
something like "if the root is disabled, I don't run any leaves"
that way you can still build all trees statically but you can choose to not run a bunch of steps at once
yeah
what's your opinion on kernel modules
i considered to just remove them to cut down on boot complexity
also might give boosts with lto
I guess it depends, I do want to have them but it'll be annoying because zig and C aren't natively compatible (so id have to have a bunch of extern wrappers)
ig the best option is to choose whether or not they're compiled in or linked
in rust it's been easy so far
do you expose a C api? or just rust?
just rust
yeah ideally I'd expose a C api
it does mangling with a buildid
so kernel abi is always the same
but i feel like it causes more trouble than it solves
fwiw zig doesnt have a defined extern abi as of yet so linked-in modules written in zig would have to work over the C abi despite all being written in zig
I think you have pretty much everything as modules?
only irqchips and serial is in kernel
ig that makes sense
i was about to say you should have the core drivers in the kernel at least
now that i started to write aarch64 drivers i realize that this might be too coarse for all the little devices
there are so many little drivers i need
I'd make modules for any "big" driver then
stuff like nvme vs ahci
ig it's hard to draw the line
exactly
in linux you can make this configurable
but cargo is really inflexible here
wait, so I can't even link zig code with zig code right?
i need a C api

no you can
its just that any things that cross the boundary have to be extern-compatible
so no error unions, slices, tagged unions, or auto structs
yeah
if you compile them in as part of the same compilation you can use zig apis tho
they should make c abi ffi items
rust has the same issue
well in rust it throws a warning about ffi safety
i should've just written in C smh 
fr
its because these modern langs tend to lean towards single compilation rather than linking in stuff ig
and static everything
so ABI isnt a priority
yeah
that's just unacceptable lol
if it wasnt still generally early in dev i would be more upset about it lol
i can't wait till i have so much aura i can just nudge the language development towards my direction ร la microsoft engineers with intel engineers

i wish c would have some macro shit to do name mangling
then you could do macro generics
wdym
theres a nonzero chance my kernel will be among if not the first zig project to do full dynamic linking and loading where everything is written in zig actually, once ive got that to the proof of concept level ill start poking the zig people about ABI stuff
like vec(unsigned int)
as a macro
and that would define a struct
can't you do this now
like anonymous structs are now equal
no
if they're declared the same
false
I can swear I saw something like this as either a gnu extension or as a c26 thing
only named structs are allowed to be redeclared if they contain the same fields
in c23 at least
idk if gnu has an extension
my main reason for using zig was generics kinda but now I realize that I don't really use them 
i only use them for containers
I don't use any arraylist/vec
i write pretty C like rust
...yknow kinda unrelated but i wonder how badly zig/llvm would implode if i mix higher and lower half stuff in the same binary somehow
how does zig cope with writing to rbx in inline asm
yeah but stop procrastinating or I will be the first
i use zig because i am chronically unable to read macros to save my life
i look at C macros and my eyes glaze over and my brain shuts down
no ABI is also annoying for thread switching
but u can just make the entry points use C abi
I think
that's what i do
but it's annoying
i make the C ABI entry point call the zig function
i shared a macro that linux uses for declaring elf notes from C with a zig dev while asking for help on something and the person is like yeah this shouldnt be too hard to do in zig and im over here and cant mentally parse the macro at all even though its simple
you dont need full abi for entry just calling convention
yeah callign convention i meant
yeah
as much as i like rust, in a kernel it has helped me very little, but in turn caused me a ton of toolchain issues and implicit UB that's harder to spot
honestly I don't even understand how that works, like wont you do context switches in the middle of zig functions?
like i know it works but idk why
the interrupt handling of the cpu handles the in the middle of functions part
is the secret
i wrote this recently
and so the actual context switch is always explicit
no because context switches occur not just in interrupts
yes but its always explicit is my point. you always explicitly call a function to perform the yield/switch
thats why it works
it took me like a week to work that out lmao
it doesnt even have to be C callconv actually, you can put the swap in inline asm and have the inline asm clobber feature do the register saves for you, but thats advanced nonsense lmao
but yeah thats the idea
this is peak zig code lol
took me a week to wrap my head around it but thats because i went straight for the advanced bullshit version with inline asm instead of a C callconv
but thats me lol
yeah
storage trick?
you declare a type so that you can declare a variable inside it
like in insert() here
oh yeah that
its so slick
it is (or can be) equivalent to a static local in C afaik
yeah but ig here I'd do it with a macro in C
i just bullshitted the compiler until i made something that worked
which uses that trick to keep the csprng state as a threadlocal static local variable
yo im curous is this the spleen or terminus font or some else? ๐ค
tbh the more the merrier, the more people are suffering trying to do dynamic linking/loading of pure zig code the more likely the zig people are to consider actually making a defined ABI for stuff
i use too much OpenBSD ๐ญ
appreciate the reply
fwiw it wasnt until last month that llvm even had a defined ABI for bitints
oh damn never heard of it
indeed does look great
i saw a guy post it on twitter the other day on netbsd and thought it looked awesome
oh thats a pretty good font yeah
nothing can beat the sun firmware font though
i forget what font i use, im not on my dev machine to check and need to leave in like 5 minutes anyway
nah nah
no one can beat openindianas tty font
isn't that just spleen
thought it was spleen at fiirst as well
i do know what my favorite pixel font is, its https://media.charlesleifer.com/playground/notes/img/z-peep-12pt.png
but it has some differences
yea but it's pretty hard to get your point across to devs
yeah
no one listened to me last time i tried improving zig ๐ญ
with what, the allocator improvements? i think that was more the team not having enough people to review shit lmao
it uses its own bitmap font
yeah
if i think about it tho and look at it, its actually kinda fine shyt
what does this do
Read the comment ๐ญ
i see
like genuinely or not
cuz the comment seems self-explanatory
nah im kidding
oh yea about that
what does the comment do
it's a pretty useful thing actually, I stole it from freebsd
i didnt know __start was a thing
finally someone who steals from the BSDs ๐
huh
the linker will generate symbols for sections that dont start with .
TIL
also jesus how do apple devs manage to implement freebsd stuff but somehow with 10x more lines
there's a freebsd file that's 600 lines, xnu implements it in 3k
I cooked up something very cool
oh?
ho?
?ho
?
hohoho
Summary
The ULE scheduler currently relies on a simple thread count (tdq_count) for load balancing decisions, this is simple but does not take into account the nature of the threads running on each...
this
linux pelt?
similar yea
yeah
i know
they have WALT
iirc PELT kinda fixes it by having a util_est too now
but anyway freebsd's target is not like android
wdym
you're aware that PELT is the linux default right?
the android people didnt like it because power savings or something
heard different stories about linux performance in workloads of this kind
this isnt even full-blown PELT, it's just an additional heuristic to do load balancing
like inversions and stuff ruining perf
basically instead of only checking the number of threads, you also check the actual CPU load of these threads
so in a case where CPU0 has 10 evil threads and CPU1 has 10 mostly idle threads it'll chose CPU1
lol lots of PRs are just straight up slop ๐
Why did you decide to implement it for freebsd instead of your own kernel
Because I will implement it in my own
But like might as well improve an actually useful kernel
I see
it's weird because they have like 10 ways to send patches
also it's funny because you can't compile freebsd from linux, so I had to boot a VM, modify the kernel and install it, then it crashes -> boot into the old kernel and try again
do this like 5 times until it works, then copy your code back from ssh over to your local machine ๐ญ
Why cant you compile it?
Can't you just run it in nested bhyve?
maybe, but atp it's easier to just reboot and check if it works 
But yeah very cool work
Did freebsd not have any per thread load tracking?
no, for load balancing they only kept track of the number of threads
And for top etc?
@inner python brought this up to me and told me this was shitty so i started looking into PELT by his suggestion
that's a different mechanism, but not used for load balancing
Isn't it also just an exponentially moving average, at least on linux? What's the difference
Ah
wait idk what you mean
do you mean the % load as reported?
I meant PELT is basically a set of ewmas
I mean both
well I'm not sure what Linux does, but FreeBSD's % estimation relies on a WMA too but it decays much slower, so it can't really be used for making balancing decisions like that, I assume Linux also does something similar (slower-moving wma for % estimation)
But yeah thats pretty cool work, i dont understand any of it (probably because i know nothing about ule)
it's not really ULE specific, right? It's a load estimation that can be used for load balancing decisions
yeah
it's basically just an ewma of the time spent runnable (running or in the runqueue) so that you can make load balancing decisions more accurately based on cpu usage vs thread count
it's simpler math than linux's because linux doesn't have ticks and does it based on periods of 1024us instead, so you end up with fractional periods etc which is trickier to handle

the next file i will autistically focus on is the scheduler
i have a bunch of ideas to improve it
holy shit i had an epiphany
I wasn't sure how to embed the slab metadata in the struct page (also hadn't really thought about it) because it's basically like so:
struct slab {
struct list_entry link;
uintptr_t base;
size_t capacity;
uint64_t bitmap[];
};
This sounded annoying cuz the bitmap is sized differently directly in the struct.
I figured out you can basically shorten it to:
struct slab {
struct list_entry link;
uint8_t kind : 1;
union {
pfn_t head_pfn; // points to slab with bitmap in it
uintptr_t bitmap; // Either an inline bitmap if capacity < 64 or a pointer to a bitmap
};
};
Capacity is redundant if we remove slab coloring (which wasnt really that useful anyway), we can store it in the zone itself.
The cool trick is that the bitmap can be allocated via a bitmap zone, which itself only embeds its own slab metadata inline (thereby removing any possible circular dependency).
I looked at XNU and they seemed to put everything in the struct page but used a crazy buddy allocator to allocate the bitmaps or something, I think this is much cleanly avoided using a zone for the bitmaps themselves and make them use inline data (although there may be another reason why they do this)
lol i might send another patch to freebsd because they don't do this
dunno why i thought about this, I was doing scheduler stuff
why do you want to include the slab meta data in the struct page?
Overall less memory usage because you mostly don't waste space on it
yeah
i do it too, its actually quite nice to have
though my slabs use a freelist instead of a bitmap so i dont need to worry about if the bitmap can be inline or not
There are reasons for doing a bitmap
yeah i know
i didnt say my freelist version was good lol
but storing in the struct page is still good either way
i wanted to do microsecond accurate PELT in my kernel instead of ticks like in freebsd
the math is mathing
i may have done something wrong, one CPU has like 300k load the other has 0 wtf
yeah that sounds a bit off
yeah the concerning one isnt the 300k its the 0
ok great it seems to work
perhaps my patch will get reviewed soon ๐
based based based
anyway I added a bunch of stuff to the scheduler which is pretty nice:
- PELT with 1024us period accuracy, which is used as:
- a primary metric for the long term load balancer
- a tiebreaker for work-stealing
- a tiebreaker for pick_cpu() when a thread wakes back up
The logic behind it being only a tiebreaker in pick_cpu() is that you wanna run ASAP even if the CPU's load avg might be high, as enqueuing on a CPU with potentially many light threads would make you wait for a while
- Each thread keeps a WMA (75% old, 25% new) of its load when it blocks so that the estimated CPU's load is also taken into account when selecting CPUs, so that a case like a few worker threads waking up periodically it doesnt show as a load=0 on that CPU
wow discord is stupid, you can't nest lists
ah also I'll need to add staleness on the affinity, if the thread hasnt ran for more than 1 second then the affinity is lost
now replace the word sum with the sigma character 
that's a thing?
huh yea
i mean its just a greek letter no?
yeah but typically it's pretty enlarged in math notation
@heavy sandal do you think you could help me with something rq
maybe, whats the thing?
for fuck's sake why is zig removing my symbols
when in release build, it strips away the storage:
comptime {
_ = r.percpu_init_set.insert(&pcpu_init);
}
this is how I call it
like wtf this is just insanely annoying
and I cant use @export sanely because I need a unique name
this is the kinda stuff that is just straight up fucking annoying and stupid
if possible id say use an empty asm block with an input or output set to the thing, i think i ran into something like this with limine protocols
hm
Make an issue
i tried asking on zulip and no one answered yet
yeah i dont have any other ideas other than to start digging with readelf/objdump
Why
i think a reasonable fix is that if linksection is explicitly set then dont optimize it away
PR time?
Does Zag not compile with master Zigc?
Which one?
Ah
because windows doesnt have ncurses
So just make it not run on binbows
might go back to ncurses honestly idk
the lazy stuff in general is annoying
wish there was a way to disable it
on a per variable basis yeah
i think this is reasonable tho
but I've never managed to actually speak to a zig guy
mhm i will start a thread on zulip perhaps, is it compiler or ecosystem
prooobably compiler tbh
Why not make an issue directly, do they really not get reviewed?
they do its just slow
zulip is like discord kinda
Ah k
yeah thats where the devs talk on things that move a bit faster than issues would be good for
tbh that might be timezone stuff too but idk
andrew is in oregon
Meanwhile C3: the dev is in the languages discord server available 24/7
mhm
ok zulip post made
time to ping every maintainer
no @heavy sandal ping every maintainer that way i can't be held accountable

lmao
if zig would add something like __COUNTER__ I could generate unique names
btw can you not just use the export keyword on the storage variable? idk if thatd work for the same reason theres been limine protocol issues before but it might
if this project wasnt like 18k lines I would probably rewrite in C, it's just annoying that 1. you cant really rely on the compiler that much 2. shit breaks so dependencies are annoying 3. types are cumbersome and verbose to use the @intFromN thing
but then I cant have any type be in there
right
like I wanna export functions thru that
actually no that doesnt work because it's still not a unique name
18k is not that much tbh
I already rewrote from C to zig I don't wanna spend time rewriting zig to C
And 18k is quite a lot for what it does lol
Are you trolling
i'm currently rewriting evyrthing in C just to see how different it is
i'm like halfway done
0 clanker
tbh clanker can do rewrites really quickly
especially from something like zig to C
the point is use 0 clanker anymore
I'd probably do it using clanker first then clean it up
i want to rid myself of that
good
fwiw my OS probably has 0 lines of useful AI code
Only tests
Idk I like zig but sometimes there's just so much bullshit for no reason
same with rust
Besides I'd have to find a new name so not doing that 
rust has many QoL things but the toolchain is sooo dogshit
tbh a lot of langs have that tbf, just in different places
also basically no ENOMEM handling if you use ::alloc
I feel like C has much less
If any
Bullshit = unneeded verbosity, fighting with the compiler/toolchain, etc
its old enough that people have thrown out the bullshit is i think what c has going tbh
I don't think there really has been much bullshit
Ever
Probably it's been cleaned up a bit
especially with C23 there's been many QoL changes
like typeof(x) for example
or constexpr + auto
but I probably won't rewrite anyway, there's like 1% chance I will. I have to use zig for aura and don't wanna find a new name
i spent a long time fighting build systems and toolchain stuff in 2012 for C stuff so i disagree here, but that shit i was doing is why stuff like meson etc have been invented since
It's stuff that already existed but standardized so to me it's not life changing
also C has a ton of random bullshit if you need msvc compat, msvc has so much hot trash and broken nonsense
i don't support broken implementations
Based
good
I think it's fair to assume a GNU C compiler
all the bullshit is contained over in msvc land where we can ignore it because its bad
i feel like in C it's truly unopinionated, you can do whatever the fuck you want
Also what I don't really like about not doing C is general compat, modules get annoying to do and you pretty much have to write it all in the same language (like zig)
wow it's almost like we have the exact same issues
even though we're using different langs
My dream language would probably be C but with a bit more modern features like stronger types etc without trying to completely reinvent it like a lot of C killer languages
C++ just has too much complexity imo
yeah no
theres a reason i havent touched c++ in years and i want to keep it that way
I love using C++ and abusing it but it gets tricky to follow
c++ is ๐ if you try to use everything
yeah
see mlibc's sysdep interface
all the C killers seem to try to be as far from C as possible and tbh its not like C is a bad foundation, you can just start closer to it and add stuff instead
There are probably languages like I'd like, like C3 or odin or whatever I haven't looked at but the ecosystem is non-existent
Everything works with C
yeah
It is
the lack of stable linkable abi is the only real thing i miss using zig tbh
ikr
It's our problem, C was made to write OSes, newer languages weren't
i do get why a brand new lang might not commit to a stable abi yet, but it is still annoying not to have
Maybe we need @long pendant 's new language to save us
zig just does not commit to anything lol
mhm
if it ever comes
mood
i think languages for writing OSes in are critically underexplored
problem is no one writes new oses lol
there are no languages designed for that anymore, only ones from the 60s/70s/80s
imo a 1.x+ language should absolutely have a standard + abi
unless you're
(which we are)
I think jackal is really good for what it is (it's basically C reskinned), I find it really elegant and simple
yeah i agree there, and zig isnt at 1.x yet so im only midlly annoyed at not having an abi yet
yeah
so GCC-RS is literally just copying rustc
reminder that zig is like 15 years old lol
crumbles into dust
i really dislike rust so tbh i didnt know that it was 1.x already tbh (as i crumble into dust at how old rust is now)
it has the major merit that it isn't "actively painful in at least a few ways to write an OS in", which distinguishes it from most others today
Have you ever tried zig?
what special does jackal have
Curious
Not much, I just like the syntax
The cool thing are the function templates thing tho
i'm only loosely familiar with it
You can still use the name zag even if the project is in C you know that right 
i followed it a little when it had an IRC channel (2017?) and andrew r kelly was in there
Basically traits but for functions
i remember he was a big fan of Cosmic Gate
But then it doesn't make sense
I think it still does
And like only Andrew hangs out on there
latterly it was more interesting to look at again because i found xerox mesa (which is in principle a very remote conceptual ancestor of jackal via pillar via modula-3) surprisingly had its exact same treatment of comptime
Yeah but it's not that useful tbh
Like I had a table to generate using math and I still ended up just precomputing it
using python
because why slow down compile times even more for no reason
Interval: TYPE = RECORD [page: PageNumber, count: PageCount];
this mesa code is showing exactly the same pattern as zig type declarations
Interval: TYPE = is just a constant declaration (TYPE is just the type of types)
@heavy sandal we just need to form an osdev cabal with direct contact to Andrew so we can make zig good
If zag turns out to be pretty good there's a good chance I'll have influence
whether or not kelly copied mesa i have no idea, but it's interesting they did the exact same thing
this of course makes Zag the modern-day Cedar OS
@fallen bobcat btw for your issue, have you tried doing verbose llvm ir and checking if the thing is in the IR or not?
nvm, someone in zulip checked that, it seems llvm/lld is killing it
@fallen bobcat btw have you tried somehow doing KEEP in the linkerscript for your set sections? since latest testing from others in zulip says its llvm/lld not zig that is removing it
the idea is to not have to rely on that, unless i can do KEEP(set_*) or something
yeah would def be ideal not to worry about it
that would in theory work yeah
https://github.com/bagggage/bamos/ i found a zig OS, to me it seems mostly vibecoded ๐
yeah ok def is
lol
What makes you think that
one line the comments are perfect english the other the comments are written in very poor english
They couldโve gotten really drunk
lol
i looked a bit at tigerbeetle's code and I want to try refactoring everything a bit so it's cleaner and higher quality (more similar to theirs)
yeah their stuff is very good quality from what ive seen
one day freebsd PR will get merged...
meanwhile im currently doing prekernel stuff a bit every day
maybe it's my code, but why does zig use so much stack ๐ญ 16kib is not enough to get through init
ok i pushed the basic prekernel stuff, only maps stuff for the kernel and loads it atm, no pfndb mapping and stuff yet
sometimes copy elision on struct init fails for some reason iirc, mostly because more aggressive copy elision has caused issues with incorrect code in the past and an extra copy is usually preferred to a crash is my only guess other than just saying it's your code
i think it's because this is a few calls deep and also logging uses a bunch of stack apparently
hm
or just formatting in general i think
depends ig, for the most part logging should just get inlined to your logfn
oh yeah no formatting is kinda like that sometimes
i wouldnt expect it to be that bad tho
formatting in zig is usually more of a code size issue than a stack one ime
ive wanted for a while to see if theres any good way to do stack size static analysis
I mean you'd get the same in C
I think this is just a standard library thing idk
maybe not
idk
zig isn't doing any hidden stack allocs, it's all about just what functions are used
and how much stack those use
does it also construct every object on the stack
ah i figured out why it was using so much stack
oh?
i did a oopsie and had const features = amd64.cpu_features; in the function
so allocating a new one on the stack
oh yeah no thatll do it
and that struct is quite big
yeah
big struct on stack go boom
declared a local of that struct type instead of getting a pointer to the global of it
yea
aka forgot the &
ig there's other stuff using the stack
19 bools, plus 48 chars, plus however big the CpuVendor type is
cpuvendor is an enum
that's nothing tho
rust uses multiple pages for stack doing nothing xd
so depends on the backing int for the enum it could be anything from 68 to 71 bytes
and then round up for alignment depending on whats after it on the stack
I've decided that maybe an initgraph thing wouldnt be that useful idk
considering how I do initialization is kinda well defined idk
id have to think about it
yeah i had the same conclusion
my init is sufficiently well defined i dont need to toposort it
well, I also ended up flattening the whole call stack a bit
now the entry point is in ex and it calls ke.init
so the stack is more shallow by like 2-3 stack frames
that might help a bit yeah
and no layering violation now 
is it better to have the whole function exported or should I have a thin callconv C function that just calls ex.init
I dont think it matters
yeah doesnt really matter
smh the fn decl is ripped from zinnia
wdym
marvin when are you joining the zaggers
id use a specific callconv instead of .c tbh, just to be explicit
can I do .sysv?
idk i want this to be portable
the loader assumes sysv
yeah thats what i do (though its like .x86_64_sysv or something like that) - i have the arch code specify that arch's calling convention
my kernel also assumes sysv everywhere
so i use the aarch64 standard one for aarch64 and sysv for x86 everywhere
and that way im never worrying about if some weird target setup i try later accidentally swaps it to a different callconv and breaks things
@vital summit consider it
instead of rewriting zinnia for the 348348th time
(note that this doesnt work for x86_32 if you mix callconvs and use llvm, as llvm for some reason refuses to allow multiple different calling conventions in a 32-bit x86 binary)
We could be the next managarm ๐ฅบ
yea but I'm retarded
You can do stuff you're comfortable with
idk what you're good at but I don't like drivers and architecture/hardware code in general
And that's not really tricky
i will write drivers for you if you can unfuck my rust scheduler 
What's the problem with it
half of it is vibed because i didn't know how to debug it
and i REALLY don't like it
i tried to understand it, but it kept breaking under SMP so i asked claude to fix it
it works, but i feel like it could be improved a lot
also, i like your design
what design
the one you sent me
the ule one
It's basically ule with ntisms stolen from mintia and a bunch of my own stuff
Why do you want to unfuck the rust code if you're rewriting in C tho
That's why you need to join the zig hype so you get a bazillion stars
i mean i can do some stuff for it
(but you made it sound like i should abandon zinnia for it)
You do what you want
i did more prekernel stuff, now it maps the pfndb and detects cpu features for the kernel
nice
I kinda want to do AP startup as well but I'm scared of duplicating ACPI code...
if you want cpu hotplug then youll need ap startup in the main kernel anyway
doesnt sound too bad to me lol
I mean I'll need it eventually anyway if I want NUMA
yeah
bleh ok fine
youll need at least the acpi table getting for numa
Cant you just make an acpi.zig file and share it
itll get culled anyway
because zig is lazy
could split the functions maybe
but yeah the structs is already a big help to reuse
https://github.com/rdmsr/zag/blob/master/src/platform/acpi/root.zig#L263-L287 like this relies on mm.p2v
which is not a loader thing
does zig support --gc-sections
yes, but also zig is lazy enough that we dont need a preprocessor while still having every single os's support in the std
if you never refer to something it doesnt even get compiled to need to be gc'd
