Skip to content

Commit e17f27e

Browse files
committed
[not_ready] Add fork() syscall, process scheduler can't handle it
1 parent 1307b26 commit e17f27e

File tree

13 files changed

+231
-14
lines changed

13 files changed

+231
-14
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ binaries: $(bt_stage1) $(bt_stage2) $(kernel_core) $(rm_static)
102102
SECTOR_COUNT_BT_STAGE1 = 1
103103
SECTOR_COUNT_SHARED_LIBRARY = 1
104104
SECTOR_COUNT_BT_STAGE2 = 12
105-
SECTOR_COUNT_KERNEL = 48
105+
SECTOR_COUNT_KERNEL = 52
106106

107107
SECTOR_START_BT_STAGE1 = 0
108108
SECTOR_START_SHARED_LIBRARY = $(shell expr $(SECTOR_START_BT_STAGE1) + $(SECTOR_COUNT_BT_STAGE1) )

include/fuzzy/kernel/process/process.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ struct Process {
3737
unsigned int blocking_pid; // TODO: make list
3838
} process_wait;
3939
} block_data; // valid if state == BLOCK
40+
41+
// schedule for IRQ0
42+
// 0 - no fork requested or last fork successful; can try fork again
43+
// 1 - fork requested; should NOT try fork for now.
44+
// -1 - last fork failed; can try fork again
45+
signed char flagirq0_fork_ready;
46+
int flagirq0_fork_newchild; // pid
4047
};
4148

4249
void process_scheduler_init();
@@ -66,6 +73,10 @@ void process_scheduler(int *_e_ip, int *_e_cs, int *_e_sp, int *_e_ss);
6673
// user space <-> kernel space data transfer helper
6774
extern void syscall_strncpy_user_to_kernel(int user_ds, char *src_es_address, char *dest_ds_address, size_t size);
6875
extern void syscall_strncpy_kernel_to_user(int user_ds, char *dest_address, char *src_address, size_t size);
76+
extern void kernel_memncpy_absolute(int dst_ds, char *dst_address, int src_ds, char *src_address, size_t size);
6977

70-
// state logic
78+
// operations
7179
int process_waitpid(unsigned int pid, unsigned int blocked_on_pid);
80+
81+
int process_fork_mark_ready(int pid);
82+
int process_fork_check_ready(int pid);

src/kernel/interrupts/timer.asm

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ global create_infant_process_irq0_stack
6767
pop fs
6868
pop es
6969
pop ds
70+
; add esp, 16
71+
; mov eax, cs
72+
; add eax, 8
73+
; mov gs, eax
74+
; mov fs, eax
75+
; mov es, eax
76+
; mov ds, eax
77+
7078

7179
mov [esp+36], ecx ; cs
7280
mov [esp+32], edi ; ip

src/kernel/interrupts/timer.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ void irq0_pit_handler(int *e_ip, int *e_cs, int *e_sp, int *e_ss) {
3939
int oldtime_ms = get_time_since_boot_ms();
4040
timer_add_ticks(ticks_jumped);
4141
int newtime_ms = get_time_since_boot_ms();
42+
43+
// yield relies on int 0x20 only
4244
process_scheduler(e_ip, e_cs, e_sp, e_ss);
4345
VERIFY_STACKGUARD();
4446
}

src/kernel/process/allocation.c

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,7 @@ static int create_infant_process_argv_stack(int user_ds, int user_sp,
123123
return user_sp;
124124
}
125125

126-
int process_create(unsigned int ppid, int argc, char *argv[]) {
127-
// returnd pid >= 0 if success
126+
static int get_cold_pid() {
128127
int pid = -1;
129128
for (int i = 0; i < MAX_PROCESS; ++i) {
130129
if(i==PID_KERNEL) continue;
@@ -133,8 +132,17 @@ int process_create(unsigned int ppid, int argc, char *argv[]) {
133132
break;
134133
}
135134
}
135+
return pid;
136+
}
137+
138+
int process_create(unsigned int ppid, int argc, char *argv[]) {
139+
// returnd pid >= 0 if success
140+
int pid = get_cold_pid();
136141
if(pid < 0) return pid;
137142
struct Process *process = &processes[pid];
143+
// reset state
144+
process->flagirq0_fork_ready = 0;
145+
process->flagirq0_fork_newchild = -1;
138146

139147
int memory_location = memmgr_app_abs_location(pid);
140148
int memory_size = memmgr_app_size(pid);
@@ -165,8 +173,12 @@ int process_create(unsigned int ppid, int argc, char *argv[]) {
165173
process->ip = 0;
166174
// initially ds == ss
167175
process->ss = get_gdt_number_from_entry_id(idt_ds_entry);
168-
process->sp = create_infant_process_argv_stack(process->ss, STACKINIT_APP, argc, argv);
169-
process->sp = create_infant_process_irq0_stack(process->ss, process->sp);
176+
if (argc > 0) {
177+
// process_create for those who don't care about stack initilization
178+
// like fork(), they will copy whole segment memory.
179+
process->sp = create_infant_process_argv_stack(process->ss, STACKINIT_APP, argc, argv);
180+
process->sp = create_infant_process_irq0_stack(process->ss, process->sp);
181+
}
170182
return pid;
171183
}
172184

@@ -176,6 +188,57 @@ void process_kill(unsigned int pid, int status) {
176188
process->state = STATE_EXIT;
177189
}
178190

191+
int process_fork_mark_ready(int pid) {
192+
struct Process *process = get_process(pid);
193+
if(process == NULL) return -2;
194+
if(process->flagirq0_fork_ready>0) return -3; // denied; fork already requested.
195+
process->flagirq0_fork_ready = 1; // success; fork requested
196+
return 0;
197+
}
198+
199+
int process_fork_check_ready(int pid) {
200+
// should be called after process_fork_mark_ready
201+
struct Process *process = get_process(pid);
202+
if(process == NULL) return -2;
203+
if(process->flagirq0_fork_ready==-1) return -3; // fork request: failed
204+
// bad state from user side
205+
if(process->flagirq0_fork_ready==1) return -4; // fork request: still waiting
206+
return process->flagirq0_fork_newchild; // fork request: success and return new pid
207+
}
208+
209+
int process_fork(unsigned int ppid) {
210+
// should be called from irq0 only.
211+
int npid = process_create(ppid, 0, NULL);
212+
if(npid < 0) return npid;
213+
struct Process *process = get_process(ppid);
214+
struct Process *nprocess = get_process(npid);
215+
216+
nprocess->state = STATE_READY;
217+
218+
nprocess->sp = process->sp;
219+
nprocess->ip = process->ip;
220+
221+
process->state = STATE_EXIT;
222+
223+
size_t size = min(
224+
memmgr_app_size(ppid),
225+
memmgr_app_size(npid)
226+
);
227+
int dst_ds = get_gdt_number_from_entry_id(get_idt_ds_entry(npid));
228+
int src_ds = get_gdt_number_from_entry_id(get_idt_ds_entry(ppid));
229+
230+
kernel_memncpy_absolute(
231+
dst_ds,
232+
0,
233+
src_ds,
234+
0,
235+
size
236+
);
237+
print_log("copy success");
238+
// PANIC(0, "A");
239+
return npid;
240+
}
241+
179242
int process_load_from_disk(int pid, int lba_index, int sector_count) {
180243
int memory_location = memmgr_app_abs_location(pid);
181244
int err = load_sectors(memory_location, 0x80, lba_index, sector_count);

src/kernel/process/process.asm

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
global syscall_strncpy_user_to_kernel
44
global syscall_strncpy_kernel_to_user
5+
global kernel_memncpy_absolute
56

67
[SECTION .text]
78

@@ -57,6 +58,34 @@ global syscall_strncpy_kernel_to_user
5758
pop ebp
5859
ret
5960

61+
kernel_memncpy_absolute:
62+
push ebp
63+
mov ebp, esp
64+
; callee save register
65+
push ebx
66+
push esi
67+
push edi
68+
push ds
69+
push es
70+
71+
mov ecx, [ebp + 0x18] ; count
72+
mov esi, [ebp + 0x14] ; src_loc
73+
mov ds, [ebp + 0x10] ; src_ds
74+
mov edi, [ebp + 0x0C] ; dest_loc
75+
mov es, [ebp + 0x08] ; dest_ds
76+
77+
; strcpy
78+
rep movsb
79+
80+
pop es
81+
pop ds
82+
pop edi
83+
pop esi
84+
pop ebx
85+
86+
pop ebp
87+
ret
88+
6089

6190
[SECTION .data]
6291
kernel_saved_stack_top db ' '

src/kernel/process/process.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,24 @@ int syscall_1_process_wait(int pid, int blocked_on_pid) {
4444
return process_waitpid(pid, blocked_on_pid);
4545
}
4646

47+
int syscall_1_process_fork(int user_pid, int op) {
48+
switch (op) {
49+
case SYSCALL_PROCESS_SUB_FORK_MARK_READY:
50+
return process_fork_mark_ready(user_pid);
51+
case SYSCALL_PROCESS_SUB_FORK_CHECK_READY:
52+
return process_fork_check_ready(user_pid);
53+
}
54+
return -1;
55+
}
56+
57+
int syscall_1_process_get(int pid, int op) {
58+
switch (op) {
59+
case SYSCALL_PROCESS_SUB_GET_PID:
60+
return pid;
61+
}
62+
return -2;
63+
}
64+
4765
int syscall_1_process_spawn_fname(unsigned int user_pid,
4866
int user_ds, char *_us_filename, char *_us_argv[]) {
4967
// User must send all PROCESS_MAX_ARGC arguments.
@@ -81,6 +99,10 @@ int syscall_1_process(int operation, int a0, int a1, int a2, int a3, int user_ds
8199
return 0;
82100
case SYSCALL_PROCESS_SUB_WAIT:
83101
return syscall_1_process_wait(user_pid, a0);
102+
case SYSCALL_PROCESS_SUB_FORK:
103+
return syscall_1_process_fork(user_pid, a0);
104+
case SYSCALL_PROCESS_SUB_GET:
105+
return syscall_1_process_get(user_pid, a0);
84106
case SYSCALL_PROCESS_SUB_SPAWN_FNAME:
85107
return syscall_1_process_spawn_fname(user_pid, user_ds, (char*)a0, (char**)a1);
86108
}

src/kernel/process/scheduler.c

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,25 @@ void process_scheduler_stash_state() {
4444
}
4545

4646
int process_scheduler_get_next_pid(int lastpid) {
47-
process_scheduler_stash_state();
4847
// execute one of the scheduling algorithm
4948
return process_scheduler_largestpid(lastpid);
5049
}
5150

51+
static void handle_fork(unsigned int ppid, struct Process *process) {
52+
if(process->flagirq0_fork_ready>0) {
53+
int npid = process_fork(ppid);
54+
if(npid<0) {
55+
process->flagirq0_fork_ready = -1; // request failed;
56+
} else {
57+
struct Process *nprocess = get_process(npid);
58+
process->flagirq0_fork_ready = 0; // request success;
59+
process->flagirq0_fork_newchild = npid;
60+
nprocess->flagirq0_fork_ready = 0; // request success;
61+
nprocess->flagirq0_fork_newchild = npid;
62+
}
63+
}
64+
}
65+
5266
void process_scheduler(int *_e_ip, int *_e_cs, int *_e_sp, int *_e_ss) {
5367
int e_ip = *_e_ip;
5468
int e_cs = *_e_cs;
@@ -59,14 +73,11 @@ void process_scheduler(int *_e_ip, int *_e_cs, int *_e_sp, int *_e_ss) {
5973
e_ss, e_sp);
6074

6175
int pid = get_idt_reverse_pid_lookup_cs(e_cs);
62-
int npid = process_scheduler_get_next_pid(pid);
63-
64-
if(npid<0) {
65-
PANIC(0, "[process_scheduler] no STATE_READY process alive");
66-
}
6776

68-
print_info("[process_scheduler] pid: %d -> %d", pid, npid);
6977
struct Process *process = get_process(pid);
78+
process_scheduler_stash_state();
79+
handle_fork(pid, process);
80+
7081
if(process->state != STATE_COLD) {
7182
// if last process is still alive
7283
process->cs = e_cs;
@@ -78,6 +89,16 @@ void process_scheduler(int *_e_ip, int *_e_cs, int *_e_sp, int *_e_ss) {
7889
// - RUNNING
7990
// - BLOCK # TODO: implement
8091

92+
int npid = process_scheduler_get_next_pid(pid);
93+
94+
if(npid<0) {
95+
PANIC(0, "[process_scheduler] no STATE_READY process alive");
96+
}
97+
98+
if(pid != npid) {
99+
print_log("[process_scheduler] pid: %d -> %d", pid, npid);
100+
}
101+
81102
struct Process *nprocess = get_process(npid);
82103
nprocess->state = STATE_RUNNING;
83104
e_cs = nprocess->cs;

src/usr/include/process.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,26 @@
22

33
#define SYSCALL_PROCESS_SUB_EXIT 0
44
#define SYSCALL_PROCESS_SUB_WAIT 1
5-
#define SYSCALL_PROCESS_SUB_SPAWN_FNAME 2
5+
#define SYSCALL_PROCESS_SUB_FORK 2
6+
#define SYSCALL_PROCESS_SUB_SPAWN_FNAME 3
7+
#define SYSCALL_PROCESS_SUB_GET 4
68

79
#define PROCESS_MAX_ARGC 6
810
#define PROCESS_MAX_ARG_LEN 32
911

12+
#define SYSCALL_PROCESS_SUB_FORK_MARK_READY 0
13+
#define SYSCALL_PROCESS_SUB_FORK_CHECK_READY 1
14+
15+
#define SYSCALL_PROCESS_SUB_GET_PID 0
16+
1017
// if non-negative value is returned
1118
// then it's the pid of the new process
1219
// otherwise it's some error code
1320
int spawnl(char *path, char *arg0, ...);
1421
int spawnv(char *path, char *argv[]);
1522

23+
int getpid();
24+
25+
int fork();
1626
void yield();
1727
int waitpid(unsigned int blocked_on_pid);

src/usr/lib/process.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,39 @@ int waitpid(unsigned int blocked_on_pid) {
6161
// keep waiting
6262
yield();
6363
}
64+
}
65+
66+
int getpid() {
67+
return SYSCALL_A2(SYSCALL_PROCESS, SYSCALL_PROCESS_SUB_GET, SYSCALL_PROCESS_SUB_GET_PID);
68+
}
69+
70+
int fork() {
71+
int mark_it = SYSCALL_A2(SYSCALL_PROCESS, SYSCALL_PROCESS_SUB_FORK, SYSCALL_PROCESS_SUB_FORK_MARK_READY);
72+
if(mark_it != 0) {
73+
// failed to mark process as fork ready, maybe it's already marked.
74+
return mark_it;
75+
}
76+
// fork requested.
77+
// let's process scheduler fork the job.
78+
printf("calling yield\n");
79+
yield();
80+
while(1);
81+
printf("yield over\n");
82+
// fork request should be complete by now.
83+
int status = SYSCALL_A2(SYSCALL_PROCESS, SYSCALL_PROCESS_SUB_FORK, SYSCALL_PROCESS_SUB_FORK_CHECK_READY);
84+
printf("fork_check_ready: %d\n", status);
85+
if(status < 0) {
86+
// request either failed
87+
// or still waiting: it's a bad state, but we are going to let that slide.
88+
return status;
89+
}
90+
// fork successful.
91+
int child_pid = status;
92+
int my_pid = getpid();
93+
if(my_pid==child_pid) {
94+
// child process
95+
return 0;
96+
}
97+
// parent process
98+
return child_pid;
6499
}

0 commit comments

Comments
 (0)