#Nyaux
1 messages · Page 20 of 1
you can also test my OS (I dont have an OS)
Please don't abandon Nyaux again
(smp is kinda complicated)
how
Race conditions (Rust kinda makes it easier) and cache-coherency (TLB issues)
i have locks on everything that is unsafe
The goal is to have no locks
Also my kernel was full of reference counting pointers, and I'm getting rid of them since they become very anoying quite quickly
In the sense that it kills the performance
I have it on my MemoryManager and terminal
its not worth completely avoiding locks either, making everything lockless can also kill performance
That is fine
But there is RCU and you can try and make things CPU-local
yeah
(I still don't have a system to properly wait for munmap to invalidate TLB on other cores)
I just realized some day that I have accidentally effectively serialized interrupts on my kernel
I have global random pools that are locked inside the irqs and then also a global lock protecting the irq handler list that is locked inside the irq handler
(I should really get rid of that because removing/adding irq handler is very rare and I can just make making sure that the irq is not getting triggered anymore when deregistering the handler the caller's responsibility)
and the random pools should just be cpu local
Just ignore us, you will feel the pain later
My irq handlers (dispatchers) are per-core and have no locks 😎
(in kernel)
where in the sdm does it take abt getting the cpuid using the cpuid instruction
which chapter
Just use this?
but what about the core number

for funny prints
also cause more information = pro
its fine i just wont have that
you should make that up yourself
ok lol
giving the cores numbers starting at 0
because the lapic id's may not be contiguous
and may not start at 0
and may be different from cpuid
or msr
(one of two I don't remember)
hehehaha
yummm
ummmm
why is the lapic address the exact same
im using read msr
to get the lapic addr
that font is ugly
give me better one then :)
the default flanterm one is good enough
where do you get it from
Oh, that is not normal
yea wtf
You are using at mut again (?)
whats wrong
damn nice
no its not ub
where is it from
rdmsr
nyaux thread is almsot at 20000 messages
lol
and you mask the bits
yes
github mentioned???
what i do
let addr = rdmsr(0x1b);
let shit = (addr & 0xfffff000) + HDDM_OFFSET.get_response().unwrap().offset();
okay sec pushing
lol
yes
iretd
is this wrong
idk if his github is iretq
print shit
okay sdc
It looks normal
On which CPU are you reading those?
oh
LMAO
😭
i forgot
im doing this on the bootstrap cpu
yea
(except when it's not (I had a bug in my kernel because of that))
where scheduler
lies
(im scared of scheduler cause now hardmode with smp)
Time has the same frequency on all CPUs btw
but it's a rewrite
*2nd
this scheduler was rewritten
without any code copied
ur scheduler looks extremely hard mode lol
I only started copying code in june
it's pretty basic
I think the code is just messy
my code indeed is messy
((my scheduler is as well))
(((oh)))
((((I have barely modified it since the day it was committed)
(((((only reason I did is because of api changes and bug fixes)))))
anyone have GOOD scheduler code thats simple and supports smp i can read?
can probably look at like any project here and find that
good code or good scheduler
good scheduler look at freebsd's ULE
for now just do round robin on each cpu
it is pretty simple
just do round robin
global lock
or per-cpu queues
nah no need for global locks
or both
pre-cpu queues are better
yea
choose a cpu sequentially at first
then in the future you can do load balancing
Like you probably don't need more than that for most uses
// choose a cpu to run
// todo: better
int cpu = rand() % cpu_count;
I did that because I wanted my drivers to be able to preempt everything else
no
curr_cpu++;
if curr_cpu >= cpu_len-1 { curr_cpu = 0}
process stores things like the pagemap, handle table and threads
managram does that (?)
handle table sorry?
table of handles
??
a handle table == a table that maps eg. fd's to actual kernel objects
what is an fd again
an opaque integer handle to a open file
what object
struct process {
...
handles: HashMap<usize, ?>
...
}
should it map to
i like hashmaps they are easy :)
whatever you need, likely you want to make it a variant
probably should be an array
variant?
should it be a dyn vnode or smthin
an enum
oh
just a fd table
but rather generic handles which can be fds
what handles can it also be
what handles also exist
other then fds
in UNIX, nothing
i see
can there be multiple handles to the same thing
handles are actually a much better design but don't tell that to unix people
or only one
but they are the same handle id or no
oh okay
so if its an fd
it should be pointing to a dyn vnode
which can be whatever
nah
huh
whats posix::file??
an open file ™️
cursor?
the write/read position within the file
that's just a class which implements the Stream 'trait', meaning you can read, write and seek on it
and that contains the offset in file?
yea
i see
I forgot why I have a stream trait but it's useful
oh yeah
I remember now
for loading elfs for example
you can pass a Stream&
meaning you could pass a byte stream or a vnode stream and it'd work the same
trait Stream {
fn read
fn write
fn seek
}
struct VNodeStream {offset: usize};
impl Stream for VNodeStream{...};
struct PosixFile {
vnode: Rc<RefCell<dyn vnode>>,
flags: VNODEFLAGS,
stream: VNodeStream
}
something like this?
can yall pin this for me so i dont forget
thanks
enum HandleType {
File(*mut PosixFile)
}
struct cpu_context {
frame: *mut Registers,
// fpu_state: todo!
}
struct perthreadcpuinfo {
kernel_stack_ptr *mut u8,
user_stack_ptr: *mut u8,
}
struct process {
vfs: *mut vfs,
pagemap: u64,
cwd: Rc<RefCell<dyn vnode>>,
pid: u64,
handles: HashMap<usize, HandleType>,
name: String,
threads: Vec<Thread>
}
struct Thread {
name: String,
tid: u64,
gs_base: *mut perthreadcpuinfo,
context: *mut cpu_context
}
tell me if theres anything else i need to add
?
where is the thread contex tinfo
*context info
perthreadcpuinfo
tbh you don't really need that inside the thread
okay i added
wym
well it depends on how your scheduler works, if you eg. use the irq handler to save the user regs and your scheduler only switches between kernel mode threads (and saves the callee saved registers on the stack) then you might not need it inside the thread struct
You need it for syscall
yea i want syscall
eh, still it doesn't have to be inside the thread
though ig if you don't want to pass the context ptr around manually then it might be nice
but like you usually don't have to pass the whole context that deep anyway
(unless you like store the syscall context inside the thread itself instead of the thread's kernel stack or smth)
I do because I store the current thread in gs
how does that affect it tho
yeah nvm
sadly no, its 48cf (the encoding for iretq;’))
adverb
From where; from what place.
"Whence came this traveler?"
From what origin or source.
"Whence comes this splendid feast?"
okay
man seek doesnt exist lol
for some reason
im probs missing a package but i dont know what it is
im on popos
sooo
man fseek
okay there
okay does whence like choose if u add set or subtract the offset?
because its from the end of the file
what
Whence::END
means that its an offset from the end of the file
and end of the file == size of the file
why would u want that
no to add an offset to the end of the file
the offset can be zero
can also be negative
i see
shouldnt shouldnt vnodestream also have vnode
or how is it gonna get the vnode
okay makes sense
why
doesn't matter really
Open it
Opening a directory is a valid operation because you can then use getdents or whatever
Open a file using a path relative to that directory
yea i see
or using a sentinel value to represent the current working directory
if off>attr.size then resize
no
why is this not good
okay
i did that
is that good
also
why do u do tn->attr.size
that wasnt modified?
so why are you reallocing the exact same size
oh this is in read
i have no idea why I even realloc there
lmao
i think I mustve copy pasted write
😭
alr
fn read(&self, buf: &mut [u8], offset: isize) -> Result<usize, UNIXERROR> {
let mut count = buf.len();
if buf.len() == 1 {
return Err(UNIXERROR::EINVAL);
}
if (offset + buf.len() as isize) as usize >= self.data.len() {
if self.data.len() <= offset as usize {
count = (offset - self.data.len() as isize) as usize
}
}
if self.data.len() == 0 {
return Err(UNIXERROR::EPERM);
}
let dest = unsafe {buf.as_mut_ptr().offset(offset)};
let src: *const u8 = self.data.as_ptr();
unsafe {
core::ptr::copy_nonoverlapping(src, dest, count)
}
return Ok(count);
}
fn write(&mut self, buf: &[u8], offset: isize) -> Result<usize, UNIXERROR> {
let size = (offset + buf.len() as isize) as usize;
if (offset + buf.len() as isize) as usize > self.data.len() as usize {
self.data.resize((offset + buf.len() as isize) as usize, 0);
}
if self.data.len() == 0 {
return Err(UNIXERROR::EPERM);
}
self.data.resize(size, 0);
let src = buf.as_ptr();
let dest = unsafe {self.data.as_mut_ptr().offset(offset)};
unsafe {
core::ptr::copy_nonoverlapping(src, dest, size);
}
// SO EASY
return Ok(size);
}
these 2 funcitions look good?
idk try them
Shouldn't you follow symlinks in a loop?
In Vnode::Type::LINK
this is in tmpfs
fn read(&self, buf: &mut [u8], offset: isize) -> Result<usize, UNIXERROR> {
let mut count = buf.len();
if buf.len() == 1 {
return Err(UNIXERROR::EINVAL);
}
if (offset + buf.len() as isize) as usize >= self.data.len() {
if self.data.len() <= offset as usize {
count = (offset - self.data.len() as isize) as usize;
}
}
if self.data.len() == 0 {
return Err(UNIXERROR::EPERM);
}
let dest = unsafe {buf.as_mut_ptr().offset(offset)};
let src: *const u8 = self.data.as_ptr();
unsafe {
core::ptr::copy_nonoverlapping(src, dest, count)
}
return Ok(count);
}
fn write(&mut self, buf: &[u8], offset: isize) -> Result<usize, UNIXERROR> {
let count = buf.len();
if (offset + buf.len() as isize) as usize > self.data.len() as usize {
self.data.resize((offset + buf.len() as isize) as usize, 0);
}
if self.data.len() == 0 {
return Err(UNIXERROR::EPERM);
}
let src = buf.as_ptr();
let dest = unsafe {self.data.as_mut_ptr().offset(offset)};
unsafe {
core::ptr::copy_nonoverlapping(src, dest, count);
}
// SO EASY
return Ok(count);
}
i dont know what im doing wrong
to be honest
im trying to read it but it seems fine
like if offset is anything other then 0
no data is given
your read is wrong
how lol
oh
that solved nothing
assertion left == right failed
left: "ello world!\n"
right: ""
also read should take a count
really?
well yeah cuz you don't handle offsets
yes?
mhm well I guess if you can get the size of &[u8] then its fine
but then that won't work for syscalls
because you can't take a &[u8] from syscalls
still fails
you wanna read maximum len bytes
what
so if offset is bigger then data.len
what do i do
like im so confused rn lol
fn read(&self, buf: &mut [u8], offset: isize, count: usize) -> Result<usize, UNIXERROR> {
let mut count = count;
if buf.len() == 1 {
return Err(UNIXERROR::EINVAL);
}
if (offset + buf.len() as isize) as usize > self.data.len() {
if self.data.len() <= offset as usize {
count = (offset - self.data.len() as isize) as usize;
}
}
if self.data.len() == 0 {
return Err(UNIXERROR::EPERM);
}
let dest = unsafe {buf.as_mut_ptr().offset(offset)};
let src: *const u8 = self.data.as_ptr();
unsafe {
core::ptr::copy_nonoverlapping(src, dest, count)
}
return Ok(count);
}
like
this is my read function rn
okay
if self.data.len() <= offset as usize { that's wrong
i see
apart from that no idea
what should it be then
okay
this isnt a very complex function lmao
if (offset + buf.len() as isize) as usize > self.data.len() {
count = (offset - self.data.len() as isize) as usize;
}
buf.len() == 1 is also wrong, what if I want to read 1 byte
something like this
yes try it
okay
if self.data.len() == 0 {
return Err(UNIXERROR::EPERM);
}
shouldnt be an error
just return 0
bro
buf+offset
that's wrong
you read N bytes from file at offset O
why are you putting N bytes in buffer at offset O
what
at this point im not gonna spoonfeed
does it make sense to write data from the beginning of the file to a buffer + offset?
no
when what you really want is to read bytes from file+offset?
yes
then fix that
what is offset
1
is there a copy_unaligned
lemme check
let mut buf = "hello world!\n".as_bytes();
thats src
i cannot print dest
as this is running in a test
so an std enviroment
idk can't you do println!("{} {}", dest src)
no
no
here
fn read(&self, buf: &mut [u8], offset: isize, count: usize) -> Result<usize, UNIXERROR> {
let mut count = count;
if buf.len() == 0 {
return Err(UNIXERROR::EINVAL);
}
if (offset + buf.len() as isize) as usize > self.data.len() {
count = (offset - self.data.len() as isize) as usize;
}
if self.data.len() == 0 {
return Ok(0)
}
let dest = unsafe {buf.as_mut_ptr()};
let src: *const u8 = unsafe {self.data.as_ptr().offset(offset)};
unsafe {
core::ptr::copy_nonoverlapping(src, dest, count)
}
return Ok(count);
}
no clue then
I shall ask mr.gpt
lmao
// Copy the data safely using slices
let src = &self.data[offset..offset + read_len];
buf[..read_len].copy_from_slice(src);
try this
I actually did think of that but i wasn't sure if slices worked
not possible cause offset is of type isize
you cannot index slices with isize
well
you can do
offset as usize...(offset + read_len) as usize
or something
that won't work for negative offsets yet but it's a start
well negative offsets wont work if you dont have a cursor anyway
I don't see you modifying it
im implementing that
well then easy
its not pushed
(self.cursor + offset) as usize...(size)
okay and how do i make negative reads working
well cursor+offset is always going to be positive
if you check for it ofc
you can't do a read at absolute -10
it's always relative to the cursor
when you get read(-10) then you do cursor+-10
idk what a shangain is
do this
it'll work
you can make offset usize
okay is this good
fn read(&self, buf: &mut [u8], offset: usize) -> Result<usize, UNIXERROR> {
let mut size = offset + buf.len() as usize;
if buf.len() == 0 {
return Err(UNIXERROR::EINVAL);
}
if (offset + buf.len()) >= self.data.len() {
size = self.data.len();
}
if self.data.len() == 0 {
return Err(UNIXERROR::EPERM);
}
let pro = &self.data[offset..size];
buf[..pro.len()].copy_from_slice(pro);
return Ok(size);
}
why is it useless?
you can just do size-offset
yea
okay
same as (offset..size).len()
fn read(&self, buf: &mut [u8], offset: usize, count: usize) -> Result<usize, UNIXERROR> {
let mut size = offset + buf.len() as usize;
if buf.len() == 0 {
return Err(UNIXERROR::EINVAL);
}
if (offset + buf.len()) >= self.data.len() {
size = self.data.len();
}
if self.data.len() == 0 {
return Err(UNIXERROR::EPERM);
}
let pro = &self.data[offset..count];
buf[..count - offset].copy_from_slice(pro);
return Ok(count);
}
does THIS function look good now
try it
wait i think i fixed a bug
fn read(&self, buf: &mut [u8], offset: usize, count: usize) -> Result<usize, UNIXERROR> {
let mut size = offset + count as usize;
if buf.len() == 0 {
return Err(UNIXERROR::EINVAL);
}
if (offset + count) >= self.data.len() {
size = self.data.len();
}
if self.data.len() == 0 {
return Err(UNIXERROR::EPERM);
}
let pro = &self.data[offset..size];
buf[..(size) - offset].copy_from_slice(pro);
return Ok(size);
}
yea this is better
wait no i did not
sec
wait why offset + count
@cinder plinth
no that's wrong
yea
should it be buf.len? orrrr
size should be count
just
size = count;
?
nvm
yea
buf[..size - offset].copy_from_slice(pro);
what about size - offset
like what if size was 1
and offset is 1
it would be 0
and you would be indexing 0
which makes sense.?
i suppose it does
no cause
if size is 2
and offset is 1
it will index 1 of the slice
so not good
what should i do then
true
lma
dont do it then
yea
mr.gpt was wrong
clearly
mr gpt is stupid
fn write(&mut self, buf: &[u8], offset: usize, count: usize) -> Result<usize, UNIXERROR> {
let size = count;
if buf.len() == 0 {
return Err(UNIXERROR::EINVAL)
}
if offset + buf.len() > self.data.len() as usize {
self.data.resize((offset + buf.len()), 0);
}
if self.data.len() == 0 {
return Err(UNIXERROR::EPERM);
}
let pro = &buf[offset..size];
self.data.copy_from_slice(pro);
// SO EASY
return Ok(size);
}
i think this is also correct
great
one sec
for WHENCE::END what should i do
trait Stream {
fn read<T>(&self, buf: &mut [u8], sizeofbut: usize) -> Result<usize, UNIXERROR>;
fn write<T>(&self, buf: &mut [u8], sizeofbut: usize) -> Result<usize, UNIXERROR>;
fn seek(&mut self, offset: isize, wh: WHENCE) -> Result<usize, UNIXERROR>;
}
struct VNodeStream {
offset: usize,
vnode: Rc<RefCell<dyn vnode>>
}
enum VNODEFLAGS {
None,
DIR,
SYMLINK,
FILE
}
enum WHENCE {
CURRENT,
SET,
END
}
impl Stream for VNodeStream{
fn read<T>(&self, buf: &mut [u8], sizeofbut: usize) -> Result<usize, UNIXERROR> {
let res = self.vnode.borrow_mut().read(buf, self.offset, sizeofbut);
return res;
}
fn seek(&mut self, offset: isize, wh: WHENCE) -> Result<usize, UNIXERROR> {
match wh {
WHENCE::CURRENT => {
self.offset = (self.offset as isize + offset) as usize;
},
WHENCE::SET => {
self.offset = (self.offset as usize)
},
WHENCE::END => {
self.offset = (self.vnode.borrow_mut().get_attrib().unwrap().size as isize + offset) as usize
}
}
Ok(self.offset)
}
fn write<T>(&self, buf: &mut [u8], sizeofbut: usize) -> Result<usize, UNIXERROR> {
let res = self.vnode.borrow_mut().read(buf, self.offset, sizeofbut);
return res;
}
}
struct PosixFile {
vnode: Rc<RefCell<dyn vnode>>,
flags: VNODEFLAGS,
stream: VNodeStream
}
is this good
i think it looks good
okay so now we have a PosixFile
eh its fine
i finished implmenting PosixFile
its time...
for the scheduler
BUM BUM BUM
yall ready?
write a completely fair scheduler implementation from linux
lmao
once I get to rewriting my scheduler I will likely make it inspirted by ULE
mathew if i get bash working tonight
will you be proud of me
😎
i doubt you will
watch me
you need to implement a scheduler, syscalls, tty, port mlibc
you cant do that at the time it is atm
im not sleeping
:)
so um
hahah
idc if i have school tmrw to be honest
i just do my classes and get home
then go sleep
then work
no because you'd be rushing everything and thats bad
okay fair
ill just work what i can
is that a good cpu queue
why
removal in the middle sucks
^
:)
do yall think i should get dev devices working before scheduler
or like xsave and friends
you can if you create a new in-kernel buffer that you copy the data to/from (like you pretty much want to do)
and tbh even if you don't you can create a slice from userspace ptr + size
True
I'm not very good at explaining things
they are just files with the vnode ops being set to whatever device specific fns
okay so if u wanted to implment a dev device for like a ps2 driver
you would just create a struct that implments the vnode ops and have that deal with the driver
?
A better example would be disk access
struct PS2Driver;
impl vnodeops for PS2Driver {
...
}
write to that file, disk gets written
read from it, you are directly reading from the storage
tty
Tty demistified
thank u
okay before i implment tty lets implment /dev/null
:)
fn read()
{
// we do nothing :)
}
is this how /dev/null works
bytes read = 0
return success

and for write just return the amount of data that it tried to write
should i make a dev fs init function
i see
Im planning on putting all filesystems in a special section that gets initialised in vfs_init
But for now a devfs_init works
should a devfs have a directory like tmpfs
yes that would work
Yeah you can have subdirs like pts
i see
so just same implmentation as tmpfs
for directorys ig?
also im gonna need some way to get drivers to hook into the read() write() functions
you already have the trait?
fair
just make a function to register a trait object to the devfs
??
wdym
as in a function that the driver can use to create a file in the devtmpfs with a file that contains its own ops
how would that look like, explain further. i really gotta understand this so i dont make a shitty implmentation as with old nyaux
fn devtmpfs_register(parent_dir: &Arc<Mutex<Box<dyn VNodeOps>>>, file: Arc<Mutex<Box<dyn VNodeOps>>>) {
// ...
}
struct Ps2Device;
impl VNodeOps for Ps2Device {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
buf.fill(0xFF);
Ok(buf.len())
}
}
``` something like this I'd imagine
well yeah it could also just be a plain arc lol
that's not the important part, but you have to protect the vnode against concurrent access somewhere, either within the higher level or in the vnode fns itself
i see
how would bro add the file to the parent dir if the only ops u can do is read write lookup and stat
you make a new op to create a file?
wait create() exists nvm
yea makes sense
fn create(&mut self, name: &str) -> Result<Rc<RefCell<dyn vfs::vnode>>, UNIXERROR> {
let dir = &mut self.files;
let ifeelsick = Rc::new(RefCell::new(tmpfsfile::default()));
dir.insert(name.to_string(), ifeelsick.clone());
return Ok(ifeelsick);
}
how my create looks anyway
though idk if that's what you would use in this case because you don't want to create a new vnode for every on-disk file you create right away or you are going to be running out of ram
what
okay should i add a new op or smthin
create_from_file or smthin
idfk
or actually nvm, for an on-disk file the vnode would just die immediately if there are no references to the returned vnode
no I think the existing one is fine
I just had to stop thinking about what happens for a second lol
how would i make it use my file i already have created or smthin
since its just gonna do devfsfile::default
or idfk
you could probably proxy the ops like astral does, as in the devfsfile would contains a field with devfsops trait object that the vnodeops fns would then call
i see
struct devfsfile {
ops: Rc<RefCell<dyn devfsops>>
}
something like this?
also should i replace all my usage of rc with arc?
and refcell with mutex?
or no
because i have smp now and like im gonna be implmenting scheduler soon ™️
maybe it could be a good idea then yeah
as well with tmpfs?
yeah with everything
okay
something like that yeah and in this case the ops don't need to be arc<mutex> because the upper vnode already is
you don't need to lock twice
what should the ops be then
Arc<dyn devfs>?
Box<dyn devfsops> would probably do
okay
wait qwinci, how do i assign the ops to the file????
wdym
like, theres no function to attach ops to a devfsfile
its initally none
its wrapped in an option
the devfsfile create function can take the ops?
but that wont follow the vnodeops trait
follow in what way
fn create(&mut self, name: &str) -> Result<Arc<Mutex<dyn vfs::vnode>>, UNIXERROR>
i cant just add another parameter
because in vnode ops ive defined fn create as that
and if i add an ops field thats like really dumb
cause most fs's wont use that parameter
ah
I'd probably just make a new separate create function specifically for the devfs that can take the ops
it doesn't have to be inside vnodeops at all
wym
well like you could do the create stuff directly inside the function that's used to register something to the devtmpfs and that function doesn't have to be a part of the vnode trait
and I don't see why you couldn't make it work using the existing create fn as well, call that inside the devtmpfs create wrapper function and then assign the ops
fn devtmpfs_register(parent_dir: &Arc<Mutex<Box<dyn VNodeOps>>>, name: &str, ops: Box<dyn DevFsOps>) {
let mut node = parent_dir.create(name);
node.ops = Some(Box::new(DevFsNode::new(ops))));
}
``` if this is how it works (?) (idk if you actually have ops as a box but you get the idea anyway)
yea thats a good way
thanks qwinci :)
wait no
its not
in create i return a arc mutex dyn vnodeops
fn create(&mut self, name: &str) -> Result<Arc<Mutex<dyn vfs::vnode>>, UNIXERROR> {
return Err(UNIXERROR::EISFILE);
}
so like
😭
yea i have no idea either
😭
how we should design this like
ig the devfsnode could have a member function for the creation of a new file and then you have the logic there
member function?
impl devfsnode {
fn dev_create(&mut self, name: &str, ops: Box<dyn devfsops> {}
}
then you do the hashmap stuff in there inserting a new vnode to the map
wtf is a
&Arc<Mutex<Box<dyn
ik 😭
atomically reference counted mutex of heap allocated object implementing VNodeOps
:)
a reference to one*
for some reason
oh yeah
reference to a reference
lmao
I mean it can avoid one refcount increment/decrement 
what did you try
one sec
and what is the problem
oh yeah its the ops itself that are returned from create lol
again that breaks vnodeops
okay actually wait i have an idea
i know how to do it lol
dwdwdw
well you could have the devfs ops field as none initially and otherwise populate the ops inside create() and then inside that dev_create downcast the vnode
you can downcast a trait object to the actual underlying object (like to a reference to an actual struct) though you do need a little helper method for that
thats with box right?
so i need to wrap everything under a box?
no it doesn't matter where its stored
but anyway there are probably other solutions in this case
it wont let call downcast
yeah because you need a helper method inside the trait that returns &mut dyn Any
how to do implment that
and the impl for that can be self
oh i see
then you can do let a: &mut mystruct = node.as_any_mut().downcast_mut().unwrap() or whatever
gotcha
and whats the impl signature
impl ? for Self
well it depends in what trait you put that method into
i put vnode
like if you want to be able to cast a vnodeops then its in vnodeops
so vnodeops for Self?
you probably already have an impl block for vnodeops
just put it there
ah yeah you literally created a new trait for it
probably best to just move the decl inside vnodeops
what
trait vnodeops {
// ...
fn as_any_mut(&mut self) -> &mut dyn Any;
}
oh hell naw
oh hell yes :)
impl vnodeops for devfsfile {
// ...
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
i see
but yeah I am pretty sure there would be ways to do what you want without needing to do it like this
whats wrong with downcasting
im not even joking
this is just
you dont write codel ike this
if you do
you fucked up terriblyu
broski u have any other ideas
no i cbf reading all of ur code
I already said one idea to you, you could just move the logic from inside create to that fn
yea and implment downcast
you wouldn't need downcast if you'd move the logic there as you'd have access to the new devfsnode object you create
in the create function?
but that cant take ops
its why I said that move the code from the create function to the devfs_register or whatever fn
though then it also means that the parent dir vnode would have to not be a trait object and instead it would be a complete type (and you'd need a new non-vnodeops lookup fn that returns that complete type), though then you could reuse that to implement the vnodeops lookup fn
its not a pointer cast
what is it then
how is it cancer
this turns rust into python
theres no performance hit anyway
wait what
what the fuck did you think it was doing?
how big is the perfomance hit
well it has to check that the object is actually what youre trying to cast it to?
and if not then panic
lol
and that is a lot of perfomance loss?
every time you call the downcast method
I don't think that's "a lot of performance loss"
but if the rust masters say it's bad, do it the correct way
and im only calling it ONCE in the entire kernel
for making devfs
ah i thought
u were calling it
on every like
idk devfs operation
or whatever
but still this is bad lol
fix it
pub trait Any: 'static {
// Required method
fn type_id(&self) -> TypeId;
}
A trait to emulate dynamic typing.```
i mean.. yes it is bad lol
langauges are typed for a reason
statically typed*
I don't type my languages
I just speak them and computer executes
wdym
im a bit confused
I guess that's something like dynamic_cast in c++
the thing he's doing
well c++ has std::any
basically but with less performance overhead (or at least I'd hope so, it wouldn't be that hard to beat c++ dynamic cast because of all the things it has to take into account
)
I mean ofc its still a little even if its just a single if but its not like that bad
???
I meant that the devfs_register function would take in a parent as an Arc<Mutex<Box<devfsnode>>> or whatever so then you cna directly insert the new node into the parent's hashmap
but if you already got it working then it works™️
I understand Mutex but what's Arc or Box
arc is an atomically reference counted object and box is just a heap allocated object
so is that like atomic shared_ptr with a lock on it
arc is basically like std::shared_ptr from c++
with a lock on the object that it holds yeah
why does it have to be an arc
why does it have to be an rc either? wouldn't a box do?
no
cause borrow rules
wont let me
what are you doing that needs this
getting the cpu context
nvm a box works fine
alright
how would i store the current thread thats running?
i need this to be per cpu
im unsure of how to do that
Too much messages; do you have TLS already?
tls?
"it depends"

