Skip to content

Commit f89f2d8

Browse files
authored
Fork documentation and comments (#281)
* fork comments and tests added * comments resolveD * comments resolved
1 parent c1ca9a6 commit f89f2d8

File tree

2 files changed

+146
-34
lines changed

2 files changed

+146
-34
lines changed

src/safeposix/syscalls/sys_calls.rs

Lines changed: 124 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use crate::safeposix::filesystem::{decref_dir, metawalk, Inode, FS_METADATA};
4343
use crate::safeposix::net::NET_METADATA;
4444
use crate::safeposix::shm::SHM_METADATA;
4545

46-
use std::sync::Arc as RustRfc;
46+
4747

4848
impl Cage {
4949
fn unmap_shm_mappings(&self) {
@@ -71,16 +71,61 @@ impl Cage {
7171
}
7272
}
7373

74+
/// ### Description
75+
///
76+
///'fork_syscall` creates a new process (cage object)
77+
/// The newly created child process is an exact copy of the
78+
/// parent process (the process that calls fork)
79+
/// apart from it's cage_id and the parent_id
80+
/// In this function we clone the mutex table, condition variables table,
81+
/// semaphore table and the file descriptors and create
82+
/// a new Cage object with these cloned tables.
83+
/// We also update the shared memory mappings - and create mappings
84+
/// from the new Cage object the the
85+
/// parent Cage object's memory mappings.
86+
///
87+
/// ### Arguments
88+
///
89+
/// It accepts one parameter:
90+
///
91+
/// * `child_cageid` : an integer representing the pid of the child process
92+
///
93+
/// ### Errors
94+
///
95+
/// There are 2 scenarios where the call to `fork_syscall` might return an error
96+
///
97+
/// * When the RawMutex::create() call fails to create a new Mutex object
98+
/// * When the RawCondvar::create() call fails to create a new Condition Variable object
99+
///
100+
/// ### Returns
101+
///
102+
/// On success it returns a value of 0, and the new child Cage object is added to Cagetable
103+
///
104+
/// ### Panics
105+
///
106+
/// This system call has no scenarios where it panics
107+
///
108+
/// To learn more about the syscall and possible error values, see
109+
/// [fork(2)](https://man7.org/linux/man-pages/man2/fork.2.html)
110+
74111
pub fn fork_syscall(&self, child_cageid: u64) -> i32 {
75-
//construct a new mutex in the child cage where each initialized mutex is in
76-
// the parent cage
112+
//Create a new mutex table that replicates the mutex table of the parent (calling) Cage object
113+
//Since the child process inherits all the locks that the parent process holds,
77114
let mutextable = self.mutex_table.read();
115+
// Initialize the child object's mutex table
78116
let mut new_mutex_table = vec![];
117+
//Loop through each element in the mutex table
118+
//Each entry in the mutex table represents a `lock` which the parent process holds
119+
//Copying them into the child's Cage exhibits the inheritance of the lock
79120
for elem in mutextable.iter() {
80121
if elem.is_some() {
122+
//If the mutex is `Some` - we create a new mutex and store it in the child's mutex table
123+
//The create method returns a new struct obejct that represents a Mutex
81124
let new_mutex_result = interface::RawMutex::create();
82125
match new_mutex_result {
126+
// If the mutex creation is successful we push it on the child's table
83127
Ok(new_mutex) => new_mutex_table.push(Some(interface::RustRfc::new(new_mutex))),
128+
// If the mutex creation returns an error, we abort the system call and return the appropriate error
84129
Err(_) => {
85130
match Errno::from_discriminant(interface::get_errno()) {
86131
Ok(i) => {
@@ -97,20 +142,30 @@ impl Cage {
97142
}
98143
}
99144
} else {
145+
// If the mutex is `None` - we mimic the same behavior in the child's mutex table
100146
new_mutex_table.push(None);
101147
}
102148
}
103149
drop(mutextable);
104150

105-
//construct a new condvar in the child cage where each initialized condvar is
106-
// in the parent cage
151+
//Construct a replica of the condition variables table in the child cage object
152+
//This table stores condition variables - which are special variables that the process
153+
//uses to determine whether certain conditions have been met or not. Threads use condition variables
154+
//to stop or resume their operation depending on the value of these variables.
155+
//Read the CondVar table of the calling process
107156
let cvtable = self.cv_table.read();
157+
// Initialize the table for the child process
108158
let mut new_cv_table = vec![];
159+
// Loop through all the variables in the parent's table
109160
for elem in cvtable.iter() {
110161
if elem.is_some() {
162+
//Create a condvar to store in the child's Cage object
163+
//Returns the condition variable struct object which implements theb signal, wait, broadcast and timed_wait methods
111164
let new_cv_result = interface::RawCondvar::create();
112165
match new_cv_result {
166+
// If the result of the creation of the RawCondVar is successful - push it onto the child's mutex table
113167
Ok(new_cv) => new_cv_table.push(Some(interface::RustRfc::new(new_cv))),
168+
// If the creation was unsucessful - return an Error
114169
Err(_) => {
115170
match Errno::from_discriminant(interface::get_errno()) {
116171
Ok(i) => {
@@ -127,18 +182,25 @@ impl Cage {
127182
}
128183
}
129184
} else {
185+
// If the value is None - mimic the behavior in the child's condition variable table
130186
new_cv_table.push(None);
131187
}
132188
}
133189
drop(cvtable);
134190

135-
//construct new cage struct with a cloned fdtable
191+
//Clone the file descriptor table in the child's Cage object
192+
//Each entry in the file descriptor table points to an open file description which
193+
//in turn references the actual inodes of the files on disk
136194
let newfdtable = init_fdtable();
195+
//Loop from 0 to maximum value of file descriptor index
137196
for fd in 0..MAXFD {
138197
let checkedfd = self.get_filedescriptor(fd).unwrap();
198+
//Get the lock for the file descriptor
139199
let unlocked_fd = checkedfd.read();
140200
if let Some(filedesc_enum) = &*unlocked_fd {
201+
// Check the type of the file descriptor
141202
match filedesc_enum {
203+
// If the fd is linked to a file
142204
File(_normalfile_filedesc_obj) => {
143205
let inodenum_option = if let File(f) = filedesc_enum {
144206
Some(f.inode)
@@ -147,8 +209,10 @@ impl Cage {
147209
};
148210

149211
if let Some(inodenum) = inodenum_option {
150-
//increment the reference count on the inode
151212
let mut inode = FS_METADATA.inodetable.get_mut(&inodenum).unwrap();
213+
//Since the child Cage also inherits the parent's fd table
214+
//We increment the reference count on the actual inodes of the files on disk
215+
//Since the child Cage is a new process that also references those files
152216
match *inode {
153217
Inode::File(ref mut f) => {
154218
f.refcount += 1;
@@ -165,52 +229,56 @@ impl Cage {
165229
}
166230
}
167231
}
232+
// If the fd is linked to a pipe increment the ref count of the pipe
168233
Pipe(pipe_filedesc_obj) => {
169234
pipe_filedesc_obj.pipe.incr_ref(pipe_filedesc_obj.flags)
170235
}
236+
// If the fd is linked to a socket increment the ref count of the socket
171237
Socket(socket_filedesc_obj) => {
172-
// checking whether this is a domain socket
238+
// Check if it is a domain socket
173239
let sock_tmp = socket_filedesc_obj.handle.clone();
174240
let mut sockhandle = sock_tmp.write();
175241
let socket_type = sockhandle.domain;
242+
//Here we only increment the reference for AF_UNIX socket type
243+
//Since these are the only sockets that have an inode associated with them
176244
if socket_type == AF_UNIX {
245+
//Increment the appropriate reference counter of the correct socket
246+
//Each socket has two pipes associated with them - a read and write pipe
247+
//Here we grab these two pipes and increment their references individually
248+
//And also increment the reference count of the socket as a whole
177249
if let Some(sockinfo) = &sockhandle.unix_info {
178250
if let Some(sendpipe) = sockinfo.sendpipe.as_ref() {
179251
sendpipe.incr_ref(O_WRONLY);
180252
}
181253
if let Some(receivepipe) = sockinfo.receivepipe.as_ref() {
182254
receivepipe.incr_ref(O_RDONLY);
183255
}
184-
if let Some(uinfo) = &mut sockhandle.unix_info {
185-
if let Inode::Socket(ref mut sock) =
186-
*(FS_METADATA.inodetable.get_mut(&uinfo.inode).unwrap())
256+
if let Inode::Socket(ref mut sock) =
257+
*(FS_METADATA.inodetable.get_mut(&sockinfo.inode).unwrap())
187258
{
188259
sock.refcount += 1;
189260
}
190-
}
191261
}
192262
}
193263
drop(sockhandle);
194-
let sock_tmp = socket_filedesc_obj.handle.clone();
195-
let mut sockhandle = sock_tmp.write();
196-
if let Some(uinfo) = &mut sockhandle.unix_info {
197-
if let Inode::Socket(ref mut sock) =
198-
*(FS_METADATA.inodetable.get_mut(&uinfo.inode).unwrap())
199-
{
200-
sock.refcount += 1;
201-
}
202-
}
203264
}
204265
_ => {}
205266
}
206267

207268
let newfdobj = filedesc_enum.clone();
208-
269+
// Insert the file descriptor object into the new file descriptor table
209270
let _insertval = newfdtable[fd as usize].write().insert(newfdobj);
210-
//add deep copied fd to fd table
271+
211272
}
212273
}
274+
275+
//We read the current working directory of the parent Cage object
213276
let cwd_container = self.cwd.read();
277+
//We try to resolve the inode of the current working directory - if the
278+
//resolution is successful we update the reference count of the current working directory
279+
//since the newly created Child cage object also references the same directory
280+
//If the resolution is not successful - the code panics since the cwd's inode cannot be resolved
281+
//correctly
214282
if let Some(cwdinodenum) = metawalk(&cwd_container) {
215283
if let Inode::Dir(ref mut cwddir) =
216284
*(FS_METADATA.inodetable.get_mut(&cwdinodenum).unwrap())
@@ -223,13 +291,16 @@ impl Cage {
223291
panic!("We changed from a directory that was not a directory in chdir!");
224292
}
225293

226-
// we grab the parent cages main threads sigset and store it at 0
227-
// we do this because we haven't established a thread for the cage yet, and dont
228-
// have a threadid to store it at this way the child can initialize the
229-
// sigset properly when it establishes its own mainthreadid
294+
// We clone the parent cage's main threads and store them and index 0
295+
// This is done since there isn't a thread established for the child Cage object yet -
296+
// And there is no threadId to store it at.
297+
// The child Cage object can then initialize and store the sigset appropriately when it establishes its own
298+
// main thread id.
230299
let newsigset = interface::RustHashMap::new();
300+
// Here we check if Lind is being run under the test suite or not
231301
if !interface::RUSTPOSIX_TESTSUITE.load(interface::RustAtomicOrdering::Relaxed) {
232-
// we don't add these for the test suite
302+
// When rustposix runs independently (not as Lind paired with NaCL runtime) we do not handle signals
303+
// The test suite runs rustposix independently and hence we do not handle signals for the test suite
233304
let mainsigsetatomic = self
234305
.sigset
235306
.get(
@@ -241,29 +312,33 @@ impl Cage {
241312
let mainsigset = interface::RustAtomicU64::new(
242313
mainsigsetatomic.load(interface::RustAtomicOrdering::Relaxed),
243314
);
315+
// Insert the parent cage object's main threads sigset and store them at index 0
244316
newsigset.insert(0, mainsigset);
245317
}
246318

247-
/*
248-
* Construct a new semaphore table in child cage which equals to the one in
249-
* the parent cage
250-
*/
319+
// Construct a new semaphore table in child cage which equals to the one in the parent cage
251320
let semtable = &self.sem_table;
252321
let new_semtable: interface::RustHashMap<
253322
u32,
254323
interface::RustRfc<interface::RustSemaphore>,
255324
> = interface::RustHashMap::new();
256-
// Loop all pairs
325+
// Loop all pairs of semaphores and insert their copies into the new semaphore table
326+
// Each pair consists of a key which is 32 bit unsigned integer
327+
// And a Semaphore Object implemented as RustSemaphore
257328
for pair in semtable.iter() {
258329
new_semtable.insert((*pair.key()).clone(), pair.value().clone());
259330
}
260331

332+
// Create a new cage object using the cloned tables and the child id passed as a parameter
261333
let cageobj = Cage {
262334
cageid: child_cageid,
263335
cwd: interface::RustLock::new(self.cwd.read().clone()),
336+
// Setting the parent to be the current Cage object
264337
parent: self.cageid,
338+
// Setting the fd table with our cloned fd table
265339
filedescriptortable: newfdtable,
266340
cancelstatus: interface::RustAtomicBool::new(false),
341+
// Intitialize IDs with the default value
267342
// This happens because self.getgid tries to copy atomic value which does not implement
268343
// "Copy" trait; self.getgid.load returns i32.
269344
getgid: interface::RustAtomicI32::new(
@@ -278,28 +353,43 @@ impl Cage {
278353
geteuid: interface::RustAtomicI32::new(
279354
self.geteuid.load(interface::RustAtomicOrdering::Relaxed),
280355
),
356+
// Clone the reverse shm mappings
281357
rev_shm: interface::Mutex::new((*self.rev_shm.lock()).clone()),
358+
// Setting the mutex tables with our copy of the mutex table
282359
mutex_table: interface::RustLock::new(new_mutex_table),
360+
// Setting the condition variables table with our copy
283361
cv_table: interface::RustLock::new(new_cv_table),
362+
// Setting the semaphores table with our copy
284363
sem_table: new_semtable,
364+
// Creating a new empty table for storing threads of the child Cage object
285365
thread_table: interface::RustHashMap::new(),
366+
// Cloning the signal handler of the parent Cage object
286367
signalhandler: self.signalhandler.clone(),
368+
// Setting the signal set with the cloned and altered sigset
287369
sigset: newsigset,
370+
// Creating a new copy for the pending signal set
288371
pendingsigset: interface::RustHashMap::new(),
372+
// Setting the main thread id to 0 - since it is uninitialized
289373
main_threadid: interface::RustAtomicU64::new(0),
374+
// Creating a new timer for the process with id = child_cageid
290375
interval_timer: interface::IntervalTimer::new(child_cageid),
291376
};
292377

293378
let shmtable = &SHM_METADATA.shmtable;
294-
//update fields for shared mappings in cage
379+
// Updating the shared mappings in the child cage object
380+
// Loop through all the reverse mappings in the new cage object
295381
for rev_mapping in cageobj.rev_shm.lock().iter() {
296382
let mut shment = shmtable.get_mut(&rev_mapping.1).unwrap();
297383
shment.shminfo.shm_nattch += 1;
384+
// Get the references of the curret cage id
298385
let refs = shment.attached_cages.get(&self.cageid).unwrap();
386+
// Copy the references
299387
let childrefs = refs.clone();
300388
drop(refs);
389+
// Create references from the new Cage object to the copied references
301390
shment.attached_cages.insert(child_cageid, childrefs);
302391
}
392+
// Inserting the child Cage object at the appropriate index in the Cage table
303393
interface::cagetable_insert(child_cageid, cageobj);
304394

305395
0

src/tests/sys_tests.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ pub mod test_sys {
1010
pub fn test_sys() {
1111
ut_lind_getpid();
1212
ut_lind_getppid();
13+
ut_lind_getegid();
14+
ut_lind_getuid();
15+
ut_lind_geteuid();
16+
ut_lind_getgid();
17+
ut_lind_fork();
1318
}
1419

1520
pub fn ut_lind_getpid() {
@@ -68,5 +73,22 @@ pub mod test_sys {
6873
lindrustfinalize()
6974
}
7075

76+
pub fn ut_lind_fork() {
77+
// Since the fork syscall is heavily tested in relation to other syscalls
78+
// we only perform simple checks for testing the sanity of the fork syscall
79+
lindrustinit(0);
80+
let cage = interface::cagetable_getref(1);
81+
// Spawn a new child object using the fork syscall
82+
cage.fork_syscall(2);
83+
// Search for the new cage object with cage_id = 2
84+
let child_cage = interface::cagetable_getref(2);
85+
// Assert the parent value is the the id of the first cage object
86+
assert_eq!(child_cage.getpid_syscall(),1);
87+
// Assert that the cage id of the child is the value passed in the original fork syscall
88+
assert_eq!(child_cage.getuid(),2);
89+
// Assert that the cwd is the same as the parent cage object
90+
assert_eq!(child_cage.cwd.read(),cage.cwd.read())
91+
}
92+
7193
}
7294

0 commit comments

Comments
 (0)