PatchworkOS  da8a090
A non-POSIX operating system.
Loading...
Searching...
No Matches
process.c
Go to the documentation of this file.
1#include <errno.h>
3
4#include <kernel/cpu/cpu.h>
5#include <kernel/cpu/gdt.h>
6#include <kernel/fs/file.h>
7#include <kernel/fs/path.h>
8#include <kernel/fs/sysfs.h>
9#include <kernel/fs/vfs.h>
10#include <kernel/log/log.h>
11#include <kernel/log/panic.h>
12#include <kernel/mem/vmm.h>
14#include <kernel/sched/thread.h>
15#include <kernel/sched/timer.h>
16#include <kernel/sched/wait.h>
17#include <kernel/sync/lock.h>
18#include <kernel/sync/rwlock.h>
19#include <kernel/fs/ctl.h>
20
21#include <assert.h>
22#include <stdatomic.h>
23#include <stdint.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <sys/io.h>
27#include <sys/list.h>
28#include <sys/math.h>
29#include <sys/proc.h>
30
32
33static _Atomic(pid_t) newPid = ATOMIC_VAR_INIT(0);
34
35static mount_t* procMount = NULL;
36static dentry_t* selfDir = NULL;
37
38static list_t zombies = LIST_CREATE(zombies);
39static clock_t nextReaperTime = CLOCKS_NEVER;
40static lock_t zombiesLock = LOCK_CREATE();
41
42static process_t* process_file_get_process(file_t* file)
43{
44 process_t* process = file->inode->private;
45 if (process == NULL)
46 {
47 LOG_DEBUG("process_file_get_process: inode private is NULL\n");
48 errno = EINVAL;
49 return NULL;
50 }
51
52 if (process == kernelProcess)
53 {
54 errno = EACCES;
55 return NULL;
56 }
57
58 return process;
59}
60
62{
63 process_t* process = process_file_get_process(file);
64 if (process == NULL)
65 {
66 return ERR;
67 }
68
69 priority_t priority = atomic_load(&process->priority);
70
71 char prioStr[MAX_NAME];
72 uint32_t length = snprintf(prioStr, MAX_NAME, "%llu", priority);
73 return BUFFER_READ(buffer, count, offset, prioStr, length);
74}
75
77{
78 (void)offset; // Unused
79
80 process_t* process = process_file_get_process(file);
81 if (process == NULL)
82 {
83 return ERR;
84 }
85
86 char prioStr[MAX_NAME];
87 if (count >= MAX_NAME)
88 {
89 errno = EINVAL;
90 return ERR;
91 }
92
93 memcpy(prioStr, buffer, count);
94 prioStr[count] = '\0';
95
96 long long int prio = atoll(prioStr);
97 if (prio < 0)
98 {
99 errno = EINVAL;
100 return ERR;
101 }
102 if (prio > PRIORITY_MAX_USER)
103 {
104 errno = EACCES;
105 return ERR;
106 }
107
108 atomic_store(&process->priority, prio);
109 return count;
110}
111
114 .write = process_prio_write,
115};
116
118{
119 process_t* process = process_file_get_process(file);
120 if (process == NULL)
121 {
122 return ERR;
123 }
124
125 path_t cwd = cwd_get(&process->cwd);
126 PATH_DEFER(&cwd);
127
128 pathname_t cwdName;
129 if (path_to_name(&cwd, &cwdName) == ERR)
130 {
131 return ERR;
132 }
133
134 uint64_t length = strlen(cwdName.string);
135 return BUFFER_READ(buffer, count, offset, cwdName.string, length);
136}
137
139{
140 (void)offset; // Unused
141
142 process_t* process = process_file_get_process(file);
143 if (process == NULL)
144 {
145 return ERR;
146 }
147
148 char cwdStr[MAX_PATH];
149 if (count >= MAX_PATH)
150 {
151 errno = EINVAL;
152 return ERR;
153 }
154
155 memcpy(cwdStr, buffer, count);
156 cwdStr[count] = '\0';
157
158 pathname_t cwdPathname;
159 if (pathname_init(&cwdPathname, cwdStr) == ERR)
160 {
161 return ERR;
162 }
163
164 path_t path = cwd_get(&process->cwd);
165 PATH_DEFER(&path);
166
167 if (path_walk(&path, &cwdPathname, &process->ns) == ERR)
168 {
169 return ERR;
170 }
171
172 if (!dentry_is_positive(path.dentry))
173 {
174 errno = ENOENT;
175 return ERR;
176 }
177
178 cwd_set(&process->cwd, &path);
179 return count;
180}
181
184 .write = process_cwd_write,
185};
186
188{
189 process_t* process = process_file_get_process(file);
190 if (process == NULL)
191 {
192 return ERR;
193 }
194
195 if (process->cmdline == NULL || process->cmdlineSize == 0)
196 {
197 return 0;
198 }
199
200 return BUFFER_READ(buffer, count, offset, process->cmdline, process->cmdlineSize);
201}
202
206
208{
209 (void)offset; // Unused
210
211 if (count == 0)
212 {
213 return 0;
214 }
215
216 process_t* process = process_file_get_process(file);
217 if (process == NULL)
218 {
219 return ERR;
220 }
221
222 LOCK_SCOPE(&process->threads.lock);
223
224 thread_t* thread = CONTAINER_OF_SAFE(list_first(&process->threads.list), thread_t, processEntry);
225 if (thread == NULL)
226 {
227 errno = EINVAL;
228 return ERR;
229 }
230
231 if (thread_send_note(thread, buffer, count) == ERR)
232 {
233 return ERR;
234 }
235
236 return count;
237}
238
242
244{
245 process_t* process = process_file_get_process(file);
246 if (process == NULL)
247 {
248 return ERR;
249 }
250
251 WAIT_BLOCK(&process->dyingQueue, atomic_load(&process->flags) & PROCESS_DYING);
252
253 char status[MAX_PATH];
254 int length = snprintf(status, sizeof(status), "%lld", atomic_load(&process->status));
255 if (length < 0)
256 {
257 return ERR;
258 }
259
260 return BUFFER_READ(buffer, count, offset, status, (uint64_t)length);
261}
262
264{
265 process_t* process = process_file_get_process(file);
266 if (process == NULL)
267 {
268 return NULL;
269 }
270
271 if (atomic_load(&process->flags) & PROCESS_DYING)
272 {
273 *revents |= POLLIN;
274 return &process->dyingQueue;
275 }
276
277 return &process->dyingQueue;
278}
279
282 .poll = process_wait_poll,
283};
284
286{
287 process_t* process = process_file_get_process(file);
288 if (process == NULL)
289 {
290 return ERR;
291 }
292
293 uint64_t userPages = space_user_page_count(&process->space);
294
295 lock_acquire(&process->threads.lock);
296 uint64_t threadCount = list_length(&process->threads.list);
297 lock_release(&process->threads.lock);
298
299 clock_t userClocks = atomic_load(&process->perf.userClocks);
300 clock_t kernelClocks = atomic_load(&process->perf.kernelClocks);
301 clock_t startTime = process->perf.startTime;
302
303 char statStr[MAX_PATH];
304 int length = snprintf(statStr, sizeof(statStr),
305 "user_clocks %llu\nkernel_clocks %llu\nstart_clocks %llu\nuser_pages %llu\nthread_count %llu", userClocks,
306 kernelClocks, startTime, userPages, threadCount);
307 if (length < 0)
308 {
309 errno = EIO;
310 return ERR;
311 }
312
313 return BUFFER_READ(buffer, count, offset, statStr, (uint64_t)length);
314}
315
318};
319
320static uint64_t process_ctl_close(file_t* file, uint64_t argc, const char** argv)
321{
322 if (argc != 2 && argc != 3)
323 {
324 errno = EINVAL;
325 return ERR;
326 }
327
328 process_t* process = process_file_get_process(file);
329 if (process == NULL)
330 {
331 return ERR;
332 }
333
334 if (argc == 2)
335 {
336 fd_t fd;
337 if (sscanf(argv[1], "%lld", &fd) != 1)
338 {
339 errno = EINVAL;
340 return ERR;
341 }
342
343 if (file_table_free(&process->fileTable, fd) == ERR)
344 {
345 return ERR;
346 }
347 }
348 else
349 {
350 fd_t minFd;
351 if (sscanf(argv[1], "%lld", &minFd) != 1)
352 {
353 errno = EINVAL;
354 return ERR;
355 }
356
357 fd_t maxFd;
358 if (sscanf(argv[2], "%lld", &maxFd) != 1)
359 {
360 errno = EINVAL;
361 return ERR;
362 }
363
364 if (file_table_free_range(&process->fileTable, minFd, maxFd) == ERR)
365 {
366 return ERR;
367 }
368 }
369
370 return 0;
371}
372
373static uint64_t process_ctl_dup2(file_t* file, uint64_t argc, const char** argv)
374{
375 if (argc != 3)
376 {
377 errno = EINVAL;
378 return ERR;
379 }
380
381 process_t* process = process_file_get_process(file);
382 if (process == NULL)
383 {
384 return ERR;
385 }
386
387 fd_t oldFd;
388 if (sscanf(argv[1], "%lld", &oldFd) != 1)
389 {
390 errno = EINVAL;
391 return ERR;
392 }
393
394 fd_t newFd;
395 if (sscanf(argv[2], "%lld", &newFd) != 1)
396 {
397 errno = EINVAL;
398 return ERR;
399 }
400
401 if (file_table_dup2(&process->fileTable, oldFd, newFd) == ERR)
402 {
403 return ERR;
404 }
405
406 return 0;
407}
408
409static uint64_t process_ctl_start(file_t* file, uint64_t argc, const char** argv)
410{
411 (void)argv; // Unused
412
413 if (argc != 1)
414 {
415 errno = EINVAL;
416 return ERR;
417 }
418
419 process_t* process = process_file_get_process(file);
420 if (process == NULL)
421 {
422 return ERR;
423 }
424
425 atomic_fetch_and(&process->flags, ~PROCESS_SUSPENDED);
427
428 return 0;
429}
430
431static uint64_t process_ctl_kill(file_t* file, uint64_t argc, const char** argv)
432{
433 (void)argv; // Unused
434
435 if (argc != 1)
436 {
437 errno = EINVAL;
438 return ERR;
439 }
440
441 process_t* process = process_file_get_process(file);
442 if (process == NULL)
443 {
444 return ERR;
445 }
446
447 process_kill(process, 0);
448
449 return 0;
450}
451
453 {"close", process_ctl_close, 2, 3},
454 {"dup2", process_ctl_dup2, 3, 3},
455 {"start", process_ctl_start, 1, 1},
456 {"kill", process_ctl_kill, 1, 1},
457 {0}
458})
459
460static uint64_t process_env_read(file_t* file, void* buffer, uint64_t count, uint64_t* offset)
461{
463
464 if (file->inode->private == NULL)
465 {
466 return 0;
467 }
468
469 return BUFFER_READ(buffer, count, offset, file->inode->private, file->inode->size);
470}
471
473{
475
476 uint64_t requiredSize = *offset + count + 1;
477 if (requiredSize > file->inode->size)
478 {
479 void* newData = realloc(file->inode->private, requiredSize);
480 if (newData == NULL)
481 {
482 return ERR;
483 }
484 memset(newData + file->inode->size, 0, requiredSize - file->inode->size);
485 file->inode->private = newData;
486 file->inode->size = requiredSize;
487 }
488
489 return BUFFER_WRITE(file->inode->private, count, offset, buffer, file->inode->size);
490}
491
493 .read = process_env_read,
494 .write = process_env_write,
495 .seek = file_generic_seek,
496};
497
498static uint64_t process_env_create(inode_t* dir, dentry_t* target, mode_t mode);
499static uint64_t process_env_remove(inode_t* parent, dentry_t* target, mode_t mode);
500static void process_env_cleanup(inode_t* inode);
501
504 .remove = process_env_remove,
505 .cleanup = process_env_cleanup,
506};
507
509{
510 if (mode & MODE_DIRECTORY)
511 {
512 errno = EINVAL;
513 return ERR;
514 }
515
516 MUTEX_SCOPE(&dir->mutex);
517
518 process_t* process = dir->private;
519 assert(process != NULL);
520
522 if (inode == NULL)
523 {
524 return ERR;
525 }
526 UNREF_DEFER(inode);
527
528 inode->private = NULL;
529 inode->size = 0;
530
531 dentry_make_positive(target, inode);
532
533 lock_acquire(&process->dentriesLock);
534 list_push_back(&process->envVars, &target->otherEntry);
535 REF(target);
536 lock_release(&process->dentriesLock);
537
538 return 0;
539}
540
542{
543 if (mode & MODE_DIRECTORY)
544 {
545 errno = EINVAL;
546 return ERR;
547 }
548
549 MUTEX_SCOPE(&dir->mutex);
550
551 process_t* process = dir->private;
552 assert(process != NULL);
553
554 lock_acquire(&process->dentriesLock);
555 list_remove(&process->envVars, &target->otherEntry);
556 UNREF(target);
557 lock_release(&process->dentriesLock);
558
559 return 0;
560}
561
562static void process_env_cleanup(inode_t* inode)
563{
564 if (inode->private != NULL)
565 {
566 free(inode->private);
567 inode->private = NULL;
568 inode->size = 0;
569 }
570}
571
572static void process_cleanup(inode_t* inode)
573{
574 process_t* process = inode->private;
575 UNREF(process);
576}
577
581
582static void process_free(process_t* process)
583{
584 LOG_DEBUG("freeing process pid=%d\n", process->id);
585 assert(list_is_empty(&process->threads.list));
586
587 while (!list_is_empty(&process->dentries))
588 {
589 dentry_t* dentry = CONTAINER_OF_SAFE(list_pop_first(&process->dentries), dentry_t, otherEntry);
590 UNREF(dentry);
591 }
592
593 if (list_length(&process->threads.list) != 0)
594 {
595 panic(NULL, "Attempt to free process pid=%llu with present threads\n", process->id);
596 }
597
598 if (process->cmdline != NULL)
599 {
600 free(process->cmdline);
601 process->cmdline = NULL;
602 process->cmdlineSize = 0;
603 }
604
605 cwd_deinit(&process->cwd);
606 file_table_deinit(&process->fileTable);
607 namespace_deinit(&process->ns);
608 space_deinit(&process->space);
609 wait_queue_deinit(&process->dyingQueue);
611 futex_ctx_deinit(&process->futexCtx);
612 free(process);
613}
614
616{
617 if (process == NULL)
618 {
619 errno = EINVAL;
620 return ERR;
621 }
622
623 if (!list_is_empty(&process->dentries))
624 {
625 return 0;
626 }
627
628 char name[MAX_NAME];
629 int ret = snprintf(name, MAX_NAME, "%d", process->id);
630 if (ret < 0 || ret >= MAX_NAME)
631 {
632 return ERR;
633 }
634
635 process->proc = sysfs_dir_new(procMount->source, name, &inodeOps, REF(process));
636 if (process->proc == NULL)
637 {
638 return ERR;
639 }
640 list_push_back(&process->dentries, &process->proc->otherEntry);
641
642 process->env = sysfs_dir_new(process->proc, "env", &envInodeOps, REF(process));
643 if (process->env == NULL)
644 {
645 goto error;
646 }
647 list_push_back(&process->dentries, &process->env->otherEntry);
648
649 dentry_t* prio = sysfs_file_new(process->proc, "prio", &inodeOps, &prioOps, REF(process));
650 if (prio == NULL)
651 {
652 goto error;
653 }
654 list_push_back(&process->dentries, &prio->otherEntry);
655
656 dentry_t* cwd = sysfs_file_new(process->proc, "cwd", &inodeOps, &cwdOps, REF(process));
657 if (cwd == NULL)
658 {
659 goto error;
660 }
661 list_push_back(&process->dentries, &cwd->otherEntry);
662
663 dentry_t* cmdline = sysfs_file_new(process->proc, "cmdline", &inodeOps, &cmdlineOps, REF(process));
664 if (cmdline == NULL)
665 {
666 goto error;
667 }
668 list_push_back(&process->dentries, &cmdline->otherEntry);
669
670 dentry_t* note = sysfs_file_new(process->proc, "note", &inodeOps, &noteOps, REF(process));
671 if (note == NULL)
672 {
673 goto error;
674 }
675 list_push_back(&process->dentries, &note->otherEntry);
676
677 dentry_t* wait = sysfs_file_new(process->proc, "wait", &inodeOps, &waitOps, REF(process));
678 if (wait == NULL)
679 {
680 goto error;
681 }
682 list_push_back(&process->dentries, &wait->otherEntry);
683
684 dentry_t* perf = sysfs_file_new(process->proc, "perf", &inodeOps, &statOps, REF(process));
685 if (perf == NULL)
686 {
687 goto error;
688 }
689 list_push_back(&process->dentries, &perf->otherEntry);
690
691 dentry_t* ctl = sysfs_file_new(process->proc, "ctl", &inodeOps, &ctlOps, REF(process));
692 if (ctl == NULL)
693 {
694 goto error;
695 }
696 list_push_back(&process->dentries, &ctl->otherEntry);
697
698 path_t selfPath = PATH_CREATE(procMount, selfDir);
699 process->self =
700 namespace_bind(&process->ns, process->proc, &selfPath, MOUNT_OVERWRITE, MODE_DIRECTORY | MODE_ALL_PERMS);
701 path_put(&selfPath);
702 if (process->self == NULL)
703 {
704 goto error;
705 }
706
707 return 0;
708
709error:
710 while (!list_is_empty(&process->dentries))
711 {
712 dentry_t* dentry = CONTAINER_OF_SAFE(list_pop_first(&process->dentries), dentry_t, otherEntry);
713 UNREF(dentry);
714 }
715 return ERR;
716}
717
719{
720 process_t* process = malloc(sizeof(process_t));
721 if (process == NULL)
722 {
723 errno = ENOMEM;
724 return NULL;
725 }
726
727 ref_init(&process->ref, process_free);
728 process->id = atomic_fetch_add(&newPid, 1);
729 atomic_init(&process->priority, priority);
730 atomic_init(&process->status, EXIT_SUCCESS);
731
734 {
735 free(process);
736 return NULL;
737 }
738
739 namespace_init(&process->ns);
740 cwd_init(&process->cwd);
741 file_table_init(&process->fileTable);
742 futex_ctx_init(&process->futexCtx);
743 perf_process_ctx_init(&process->perf);
744 wait_queue_init(&process->suspendQueue);
745 wait_queue_init(&process->dyingQueue);
746 atomic_init(&process->flags, PROCESS_NONE);
747
748 process->threads.newTid = 0;
749 list_init(&process->threads.list);
750 lock_init(&process->threads.lock);
751
752 list_entry_init(&process->zombieEntry);
753
754 process->self = NULL;
755 process->proc = NULL;
756 process->env = NULL;
757 list_init(&process->dentries);
758 list_init(&process->envVars);
759 lock_init(&process->dentriesLock);
760 process->cmdline = NULL;
761 process->cmdlineSize = 0;
762
763 if (process->id != 0) // Delay kernel process /proc dir init
764 {
765 if (process_dir_init(process) == ERR)
766 {
767 process_free(process);
768 return NULL;
769 }
770 }
771
772 LOG_DEBUG("created process pid=%d\n", process->id);
773 return process;
774}
775
776void process_kill(process_t* process, int32_t status)
777{
778 lock_acquire(&process->threads.lock);
779
780 if (atomic_fetch_or(&process->flags, PROCESS_DYING) & PROCESS_DYING)
781 {
782 lock_release(&process->threads.lock);
783 return;
784 }
785
786 atomic_store(&process->status, status);
787
788 uint64_t killCount = 0;
789 thread_t* thread;
790 LIST_FOR_EACH(thread, &process->threads.list, processEntry)
791 {
792 thread_send_note(thread, "kill", 4);
793 killCount++;
794 }
795
796 if (killCount > 0)
797 {
798 LOG_DEBUG("sent kill note to %llu threads in process pid=%d\n", killCount, process->id);
799 }
800
801 lock_release(&process->threads.lock);
802
803 // Anything that another process could be waiting on or that could hold a reference to the process must be cleaned
804 // up here.
805 cwd_clear(&process->cwd);
807 namespace_clear(&process->ns);
808
809 wait_unblock(&process->dyingQueue, WAIT_ALL, EOK);
810
811 lock_acquire(&zombiesLock);
812 list_push_back(&zombies, &REF(process)->zombieEntry);
813 nextReaperTime = sys_time_uptime() + CONFIG_PROCESS_REAPER_INTERVAL; // Delay reaper run
814 lock_release(&zombiesLock);
815}
816
818{
819 if (dest == NULL || src == NULL)
820 {
821 errno = EINVAL;
822 return ERR;
823 }
824
826 LOCK_SCOPE(&dest->dentriesLock);
827
828 if (!list_is_empty(&dest->envVars))
829 {
830 errno = EBUSY;
831 return ERR;
832 }
833
834 dentry_t* srcDentry;
835 LIST_FOR_EACH(srcDentry, &src->envVars, otherEntry)
836 {
838 if (inode == NULL)
839 {
840 return ERR;
841 }
842 UNREF_DEFER(inode);
843
844 MUTEX_SCOPE(&srcDentry->inode->mutex);
845 if (srcDentry->inode->private != NULL)
846 {
847 inode->private = malloc(srcDentry->inode->size);
848 if (inode->private == NULL)
849 {
850 return ERR;
851 }
852 memcpy(inode->private, srcDentry->inode->private, srcDentry->inode->size);
853 inode->size = srcDentry->inode->size;
854 }
855
856 dentry_t* dentry = dentry_new(srcDentry->inode->superblock, dest->env, srcDentry->name);
857 if (dentry == NULL)
858 {
859 return ERR;
860 }
861
862 dentry_make_positive(dentry, inode);
863 list_push_back(&dest->envVars, &dentry->otherEntry);
864 }
865
866 return 0;
867}
868
869uint64_t process_set_cmdline(process_t* process, char** argv, uint64_t argc)
870{
871 if (process == NULL)
872 {
873 errno = EINVAL;
874 return ERR;
875 }
876
877 if (argv == NULL || argc == 0)
878 {
879 return 0;
880 }
881
882 uint64_t totalSize = 0;
883 for (uint64_t i = 0; i < argc; i++)
884 {
885 if (argv[i] == NULL)
886 {
887 break;
888 }
889 totalSize += strlen(argv[i]) + 1;
890 }
891
892 if (totalSize == 0)
893 {
894 return 0;
895 }
896
897 char* cmdline = malloc(totalSize);
898 if (cmdline == NULL)
899 {
900 errno = ENOMEM;
901 return ERR;
902 }
903
904 char* dest = cmdline;
905 for (uint64_t i = 0; i < argc; i++)
906 {
907 if (argv[i] == NULL)
908 {
909 break;
910 }
911 uint64_t len = strlen(argv[i]) + 1;
912 memcpy(dest, argv[i], len);
913 dest += len;
914 }
915
916 if (process->cmdline != NULL)
917 {
918 free(process->cmdline);
919 }
920
921 process->cmdline = cmdline;
922 process->cmdlineSize = totalSize;
923
924 return 0;
925}
926
928{
929 LOCK_SCOPE(&process->threads.lock);
930
931 thread_t* thread;
932 LIST_FOR_EACH(thread, &process->threads.list, processEntry)
933 {
934 if (thread->id == tid)
935 {
936 return true;
937 }
938 }
939
940 return false;
941}
942
944{
945 if (kernelProcess == NULL)
946 {
948 if (kernelProcess == NULL)
949 {
950 panic(NULL, "Failed to create kernel process");
951 }
952 LOG_INFO("kernel process initialized with pid=%d\n", kernelProcess->id);
953 }
954
955 return kernelProcess;
956}
957
959{
962 if (procMount == NULL)
963 {
964 panic(NULL, "Failed to mount /proc filesystem");
965 }
966
967 selfDir = sysfs_dir_new(procMount->source, "self", NULL, NULL);
968 if (selfDir == NULL)
969 {
970 panic(NULL, "Failed to create /proc/self directory");
971 }
972
974
975 // Kernel process was created before sysfs was initialized, so we have to delay this until now.
977 {
978 panic(NULL, "Failed to create /proc/[pid] directory for kernel process");
979 }
980}
981
982static void process_reaper(void* arg)
983{
984 (void)arg;
985
986 while (1)
987 {
989
990 lock_acquire(&zombiesLock);
992 if (uptime < nextReaperTime)
993 {
994 lock_release(&zombiesLock);
995 continue;
996 }
997 nextReaperTime = CLOCKS_NEVER;
998
999 list_t localZombies = LIST_CREATE(localZombies);
1000
1001 while (!list_is_empty(&zombies))
1002 {
1003 process_t* process = CONTAINER_OF(list_pop_first(&zombies), process_t, zombieEntry);
1004 list_push_back(&localZombies, &process->zombieEntry);
1005 }
1006 lock_release(&zombiesLock);
1007
1008 while (!list_is_empty(&localZombies))
1009 {
1010 process_t* process = CONTAINER_OF(list_pop_first(&localZombies), process_t, zombieEntry);
1011
1012 while (!list_is_empty(&process->dentries))
1013 {
1014 dentry_t* dentry = CONTAINER_OF_SAFE(list_pop_first(&process->dentries), dentry_t, otherEntry);
1015 UNREF(dentry);
1016 }
1017
1018 while (!list_is_empty(&process->envVars))
1019 {
1020 dentry_t* dentry = CONTAINER_OF_SAFE(list_pop_first(&process->envVars), dentry_t, otherEntry);
1021 UNREF(dentry);
1022 }
1023
1024 UNREF(process->self);
1025 process->self = NULL;
1026
1027 UNREF(process);
1028 }
1029 }
1030}
1031
1033{
1035 {
1036 panic(NULL, "Failed to create process reaper thread");
1037 }
1038}
1039
1041{
1042 return sched_process()->id;
1043}
#define MAX_NAME
Maximum length of names.
Definition MAX_NAME.h:11
#define MAX_PATH
Maximum length of filepaths.
Definition MAX_PATH.h:11
#define assert(expression)
Definition assert.h:29
#define CLOCKS_NEVER
Definition clock_t.h:16
static clock_t startTime
Definition clock.c:5
#define SYSCALL_DEFINE(num, returnType,...)
Macro to define a syscall.
Definition syscall.h:144
@ SYS_GETPID
Definition syscall.h:70
void perf_process_ctx_init(perf_process_ctx_t *ctx)
Initializes a per-process performance context.
Definition perf.c:123
#define CTL_STANDARD_OPS_DEFINE(name,...)
Helper macro to define a standard ctl file operations structure.
Definition ctl.h:49
void cwd_set(cwd_t *cwd, const path_t *newPath)
Set the current working directory.
Definition cwd.c:44
void cwd_init(cwd_t *cwd)
Initialize a CWD structure.
Definition cwd.c:5
void cwd_clear(cwd_t *cwd)
Clear the current working directory.
Definition cwd.c:51
path_t cwd_get(cwd_t *cwd)
Get the current working directory.
Definition cwd.c:18
void cwd_deinit(cwd_t *cwd)
Deinitialize a CWD structure.
Definition cwd.c:11
void dentry_make_positive(dentry_t *dentry, inode_t *inode)
Make a dentry positive by associating it with an inode.
Definition dentry.c:226
dentry_t * dentry_new(superblock_t *superblock, dentry_t *parent, const char *name)
Create a new dentry.
Definition dentry.c:114
bool dentry_is_positive(dentry_t *dentry)
Check if a dentry is positive.
Definition dentry.c:243
fd_t file_table_dup2(file_table_t *table, fd_t oldFd, fd_t newFd)
Duplicate a file descriptor to a specific file descriptor.
Definition file_table.c:172
uint64_t file_table_free(file_table_t *table, fd_t fd)
Free a file descriptor.
Definition file_table.c:72
void file_table_close_all(file_table_t *table)
Close all files in the file table.
Definition file_table.c:235
void file_table_init(file_table_t *table)
Initialize a file table.
Definition file_table.c:7
void file_table_deinit(file_table_t *table)
Deinitialize a file table.
Definition file_table.c:17
uint64_t file_table_free_range(file_table_t *table, fd_t min, fd_t max)
Free a range of file descriptors.
Definition file_table.c:94
uint64_t file_generic_seek(file_t *file, int64_t offset, seek_origin_t origin)
Helper function for basic seeking.
Definition file.c:92
inode_t * inode_new(superblock_t *superblock, inode_number_t number, inode_type_t type, const inode_ops_t *ops, const file_ops_t *fileOps)
Create a new inode.
Definition inode.c:41
void namespace_init(namespace_t *ns)
Initializes a namespace.
Definition namespace.c:100
mount_t * namespace_bind(namespace_t *ns, dentry_t *source, path_t *target, mount_flags_t flags, mode_t mode)
Bind a source dentry to a target path in a namespace.
Definition namespace.c:259
void namespace_deinit(namespace_t *ns)
Clear and deinitialize a namespace.
Definition namespace.c:111
void namespace_clear(namespace_t *ns)
Clears all mounts from a namespace.
Definition namespace.c:306
mode_t
Path flags and permissions.
Definition path.h:74
void path_put(path_t *path)
Put a path.
Definition path.c:246
#define PATH_CREATE(inMount, inDentry)
Helper to create a path.
Definition path.h:208
#define PATH_DEFER(path)
Defer path put.
Definition path.h:97
uint64_t path_walk(path_t *path, const pathname_t *pathname, namespace_t *ns)
Walk a pathname to a path.
Definition path.c:347
uint64_t pathname_init(pathname_t *pathname, const char *string)
Initialize a pathname.
Definition path.c:89
uint64_t path_to_name(const path_t *path, pathname_t *pathname)
Convert a path to a pathname.
Definition path.c:522
@ MODE_ALL_PERMS
Definition path.h:87
@ MODE_DIRECTORY
Definition path.h:84
NORETURN void panic(const interrupt_frame_t *frame, const char *format,...)
Panic the kernel, printing a message and halting.
Definition panic.c:266
#define LOG_INFO(format,...)
Definition log.h:106
#define LOG_DEBUG(format,...)
Definition log.h:100
uint64_t space_user_page_count(space_t *space)
Get the number of user pages allocated in the address space.
Definition space.c:766
void space_deinit(space_t *space)
Deinitializes a virtual address space.
Definition space.c:122
uint64_t space_init(space_t *space, uintptr_t startAddress, uintptr_t endAddress, space_flags_t flags)
Initializes a virtual address space.
Definition space.c:64
@ SPACE_MAP_KERNEL_HEAP
Map the kernel heap into the address space.
Definition space.h:36
@ SPACE_MAP_IDENTITY
Map the identity mapped physical memory into the address space.
Definition space.h:37
@ SPACE_MAP_KERNEL_BINARY
Map the kernel binary into the address space.
Definition space.h:35
#define VMM_USER_SPACE_MAX
The maximum address for user space.
Definition vmm.h:74
#define VMM_USER_SPACE_MIN
The minimum address for user space.
Definition vmm.h:75
process_t * process_new(priority_t priority)
Allocates and initializes a new process.
Definition process.c:718
void process_reaper_init(void)
Initializes the process reaper.
Definition process.c:1032
process_t * process_get_kernel(void)
Gets the kernel process.
Definition process.c:943
bool process_has_thread(process_t *process, tid_t tid)
Checks if a process has a thread with the specified thread ID.
Definition process.c:927
void process_procfs_init(void)
Initializes the /proc directory.
Definition process.c:958
uint64_t process_set_cmdline(process_t *process, char **argv, uint64_t argc)
Sets the command line arguments for a process.
Definition process.c:869
uint64_t process_copy_env(process_t *dest, process_t *src)
Copies the environment variables from one process to another.
Definition process.c:817
void process_kill(process_t *process, int32_t status)
Kills a process.
Definition process.c:776
@ PROCESS_NONE
Definition process.h:148
@ PROCESS_DYING
Definition process.h:149
@ PROCESS_SUSPENDED
Definition process.h:150
uint64_t thread_send_note(thread_t *thread, const void *buffer, uint64_t count)
Send a note to a thread.
Definition thread.c:161
tid_t thread_kernel_create(thread_kernel_entry_t entry, void *arg)
Creates a new thread that runs in kernel mode and submits it to the scheduler.
Definition thread.c:97
uint64_t wait_unblock(wait_queue_t *queue, uint64_t amount, errno_t err)
Unblock threads waiting on a wait queue.
Definition wait.c:296
void wait_queue_deinit(wait_queue_t *queue)
Deinitialize wait queue.
Definition wait.c:44
#define WAIT_ALL
Used to indicate that the wait should unblock all waiting threads.
Definition wait.h:40
void wait_queue_init(wait_queue_t *queue)
Initialize wait queue.
Definition wait.c:38
#define WAIT_BLOCK(queue, condition)
Blocks until the condition is true, will test the condition on every wakeup.
Definition wait.h:48
process_t * sched_process(void)
Retrieves the process of the currently running thread.
Definition sched.c:620
uint64_t sched_nanosleep(clock_t timeout)
Sleeps the current thread for a specified duration in nanoseconds.
Definition sched.c:638
void futex_ctx_deinit(futex_ctx_t *ctx)
Deinitialize a per-process futex context. *.
Definition futex.c:22
void futex_ctx_init(futex_ctx_t *ctx)
Initialize a per-process futex context.
Definition futex.c:16
static void lock_init(lock_t *lock)
Initializes a lock.
Definition lock.h:86
#define LOCK_CREATE()
Create a lock initializer.
Definition lock.h:68
#define LOCK_SCOPE(lock)
Acquires a lock for the reminder of the current scope.
Definition lock.h:57
static void lock_release(lock_t *lock)
Releases a lock.
Definition lock.h:146
static void lock_acquire(lock_t *lock)
Acquires a lock, blocking until it is available.
Definition lock.h:103
#define MUTEX_SCOPE(mutex)
Acquires a mutex for the reminder of the current scope.
Definition mutex.h:23
clock_t sys_time_uptime(void)
Time since boot.
Definition sys_time.c:99
#define UNREF_DEFER(ptr)
RAII-style cleanup for scoped references.
Definition ref.h:54
static void ref_init(ref_t *ref, void *free)
Initialize a reference counter.
Definition ref.h:92
#define REF(ptr)
Increment reference count.
Definition ref.h:65
#define UNREF(ptr)
Decrement reference count.
Definition ref.h:80
#define BUFFER_READ(buffer, count, offset, src, size)
Helper macros for implementing file operations dealing with simple buffers.
Definition vfs.h:192
#define BUFFER_WRITE(buffer, count, offset, src, size)
Helper macro for implementing file operations dealing with simple buffer writes.
Definition vfs.h:210
uint64_t vfs_id_get(void)
Generates a new unique ID, to be used for any VFS object.
Definition vfs.c:765
#define CONFIG_PROCESS_REAPER_INTERVAL
Process reaper interval configuration.
Definition config.h:153
#define ENOENT
No such file or directory.
Definition errno.h:42
#define EINVAL
Invalid argument.
Definition errno.h:142
#define ENOMEM
Out of memory.
Definition errno.h:92
#define EIO
I/O error.
Definition errno.h:57
#define EBUSY
Device or resource busy.
Definition errno.h:112
#define errno
Error number variable.
Definition errno.h:27
#define EACCES
Permission denied.
Definition errno.h:97
#define EOK
No error.
Definition errno.h:32
poll_events_t
Poll events type.
Definition io.h:257
@ MOUNT_PROPAGATE_PARENT
Propagate the mount to parent namespaces.
Definition io.h:490
@ MOUNT_OVERWRITE
Overwrite any existing mount at the mountpoint.
Definition io.h:492
@ MOUNT_PROPAGATE_CHILDREN
Propagate the mount to child namespaces.
Definition io.h:491
@ INODE_FILE
Is a file.
Definition io.h:314
@ POLLIN
File descriptor is ready to read.
Definition io.h:259
#define LIST_FOR_EACH(elem, list, member)
Iterates over a list.
Definition list.h:63
static list_entry_t * list_first(list_t *list)
Gets the first entry in the list without removing it.
Definition list.h:417
static list_entry_t * list_pop_first(list_t *list)
Pops the first entry from the list.
Definition list.h:375
static uint64_t list_length(list_t *list)
Gets the length of the list.
Definition list.h:246
static void list_push_back(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:343
#define LIST_CREATE(name)
Creates a list initializer.
Definition list.h:174
static void list_remove(list_t *list, list_entry_t *entry)
Removes a list entry from its current list.
Definition list.h:315
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:227
static void list_entry_init(list_entry_t *entry)
Initializes a list entry.
Definition list.h:182
static void list_init(list_t *list)
Initializes a list.
Definition list.h:196
#define PRIORITY_MAX_USER
The maximum priority user space is allowed to specify, inclusive.
Definition proc.h:49
clock_t uptime(void)
System call for retreving the time since boot.
Definition uptime.c:6
#define PRIORITY_MAX
The maximum priority value, inclusive.
Definition proc.h:48
uint8_t priority_t
Priority type.
Definition proc.h:46
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
#define CONTAINER_OF(ptr, type, member)
Container of macro.
__UINT64_TYPE__ tid_t
Thread Identifier.
Definition tid_t.h:12
__UINT64_TYPE__ fd_t
A file descriptor.
Definition fd_t.h:12
__UINT64_TYPE__ pid_t
Process Identifier.
Definition pid_t.h:11
#define CONTAINER_OF_SAFE(ptr, type, member)
Safe container of macro.
__UINT64_TYPE__ clock_t
A nanosecond time.
Definition clock_t.h:13
static dentry_t * file
Definition log_file.c:22
EFI_PHYSICAL_ADDRESS buffer
Definition mem.c:15
static uint64_t process_dir_init(process_t *process)
Definition process.c:615
static uint64_t process_ctl_dup2(file_t *file, uint64_t argc, const char **argv)
Definition process.c:373
static inode_ops_t inodeOps
Definition process.c:578
static uint64_t process_cmdline_read(file_t *file, void *buffer, uint64_t count, uint64_t *offset)
Definition process.c:187
static uint64_t process_env_create(inode_t *dir, dentry_t *target, mode_t mode)
Definition process.c:508
static void process_env_cleanup(inode_t *inode)
Definition process.c:562
static void process_cleanup(inode_t *inode)
Definition process.c:572
static wait_queue_t * process_wait_poll(file_t *file, poll_events_t *revents)
Definition process.c:263
static uint64_t process_env_remove(inode_t *parent, dentry_t *target, mode_t mode)
Definition process.c:541
static file_ops_t noteOps
Definition process.c:239
static uint64_t process_ctl_close(file_t *file, uint64_t argc, const char **argv)
Definition process.c:320
static file_ops_t envFileOps
Definition process.c:492
static uint64_t process_wait_read(file_t *file, void *buffer, uint64_t count, uint64_t *offset)
Definition process.c:243
static file_ops_t prioOps
Definition process.c:112
static process_t * kernelProcess
Definition process.c:31
static uint64_t process_note_write(file_t *file, const void *buffer, uint64_t count, uint64_t *offset)
Definition process.c:207
static uint64_t process_stat_read(file_t *file, void *buffer, uint64_t count, uint64_t *offset)
Definition process.c:285
static uint64_t process_ctl_kill(file_t *file, uint64_t argc, const char **argv)
Definition process.c:431
static void process_reaper(void *arg)
Definition process.c:982
static uint64_t process_prio_write(file_t *file, const void *buffer, uint64_t count, uint64_t *offset)
Definition process.c:76
static uint64_t process_ctl_start(file_t *file, uint64_t argc, const char **argv)
Definition process.c:409
static void process_free(process_t *process)
Definition process.c:582
static file_ops_t cwdOps
Definition process.c:182
static inode_ops_t envInodeOps
Definition process.c:502
static uint64_t process_prio_read(file_t *file, void *buffer, uint64_t count, uint64_t *offset)
Definition process.c:61
static file_ops_t waitOps
Definition process.c:280
static file_ops_t statOps
Definition process.c:316
static uint64_t process_env_write(file_t *file, const void *buffer, uint64_t count, uint64_t *offset)
Definition process.c:472
static uint64_t process_cwd_read(file_t *file, void *buffer, uint64_t count, uint64_t *offset)
Definition process.c:117
static uint64_t process_cwd_write(file_t *file, const void *buffer, uint64_t count, uint64_t *offset)
Definition process.c:138
static file_ops_t cmdlineOps
Definition process.c:203
static atomic_long count
Definition main.c:10
#define atomic_store(object, desired)
Definition stdatomic.h:289
#define atomic_fetch_or(object, operand)
Definition stdatomic.h:285
#define _Atomic(T)
Definition stdatomic.h:59
#define atomic_load(object)
Definition stdatomic.h:288
#define ATOMIC_VAR_INIT(value)
Definition stdatomic.h:74
#define atomic_fetch_and(object, operand)
Definition stdatomic.h:284
#define atomic_fetch_add(object, operand)
Definition stdatomic.h:283
#define atomic_init(obj, value)
Definition stdatomic.h:75
__UINT32_TYPE__ uint32_t
Definition stdint.h:15
__INT32_TYPE__ int32_t
Definition stdint.h:14
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
_PUBLIC int sscanf(const char *_RESTRICT s, const char *_RESTRICT format,...)
Definition sscanf.c:4
_PUBLIC int snprintf(char *_RESTRICT s, size_t n, const char *_RESTRICT format,...)
Definition snprintf.c:3
_PUBLIC void * realloc(void *ptr, size_t size)
Definition realloc.c:13
#define EXIT_SUCCESS
Definition stdlib.h:46
_PUBLIC long long int atoll(const char *nptr)
Definition atoll.c:8
_PUBLIC void * malloc(size_t size)
Definition malloc.c:5
_PUBLIC void free(void *ptr)
Definition free.c:11
_PUBLIC void * memcpy(void *_RESTRICT s1, const void *_RESTRICT s2, size_t n)
Definition memcpy.c:61
_PUBLIC size_t strlen(const char *s)
Definition strlen.c:3
_PUBLIC void * memset(void *s, int c, size_t n)
Definition memset.c:4
Directory entry structure.
Definition dentry.h:84
inode_t * inode
Will be NULL if the dentry is negative, once positive it will never be NULL.
Definition dentry.h:88
char name[MAX_NAME]
Constant after creation.
Definition dentry.h:87
list_entry_t otherEntry
Made available for use by any other subsystems for convenience.
Definition dentry.h:98
File operations structure.
Definition file.h:54
uint64_t(* write)(file_t *file, const void *buffer, uint64_t count, uint64_t *offset)
Definition file.h:59
uint64_t(* read)(file_t *file, void *buffer, uint64_t count, uint64_t *offset)
Definition file.h:58
File structure.
Definition file.h:39
Inode operations structure.
Definition inode.h:80
void(* cleanup)(inode_t *inode)
Cleanup function called when the inode is being freed.
Definition inode.h:132
uint64_t(* create)(inode_t *dir, dentry_t *target, mode_t mode)
Handles both directories and files depending on mode.
Definition inode.h:102
Inode structure.
Definition inode.h:54
mutex_t mutex
Definition inode.h:70
void * private
Definition inode.h:66
superblock_t * superblock
Constant after creation.
Definition inode.h:67
uint64_t size
Definition inode.h:60
A doubly linked list.
Definition list.h:49
A simple ticket lock implementation.
Definition lock.h:43
Mount structure.
Definition mount.h:44
dentry_t * source
The dentry to appear at target once mounted, usually the root dentry of the mounted filesystem.
Definition mount.h:48
Path structure.
Definition path.h:125
dentry_t * dentry
Definition path.h:127
Pathname structure.
Definition path.h:137
char string[MAX_PATH]
Definition path.h:138
clock_t startTime
The time when the process was started.
Definition perf.h:67
Process structure.
Definition process.h:158
mount_t * self
The /proc/self bind mount.
Definition process.h:174
file_table_t fileTable
Definition process.h:166
namespace_t ns
Definition process.h:164
list_t envVars
List of dentries in the /proc/[pid]/env/ directory.
Definition process.h:178
futex_ctx_t futexCtx
Definition process.h:167
ref_t ref
Definition process.h:159
wait_queue_t suspendQueue
Definition process.h:169
perf_process_ctx_t perf
Definition process.h:168
uint64_t cmdlineSize
Definition process.h:181
char * cmdline
Definition process.h:180
dentry_t * proc
The /proc/[pid] directory, also stored in dentries for convenience.
Definition process.h:175
space_t space
Definition process.h:163
list_entry_t zombieEntry
Definition process.h:173
pid_t id
Definition process.h:160
list_t dentries
List of dentries in the /proc/[pid]/ directory.
Definition process.h:177
cwd_t cwd
Definition process.h:165
dentry_t * env
The /proc/[pid]/env directory, also stored in dentries for convenience.
Definition process.h:176
process_threads_t threads
Definition process.h:172
lock_t dentriesLock
Definition process.h:179
wait_queue_t dyingQueue
Definition process.h:170
Thread of execution structure.
Definition thread.h:63
tid_t id
The thread id, unique within a process_t.
Definition thread.h:66
The primitive that threads block on.
Definition wait.h:182
mount_t * sysfs_mount_new(const path_t *parent, const char *name, namespace_t *ns, mount_flags_t flags, mode_t mode, const superblock_ops_t *superblockOps)
Mount a new instance of SysFS.
Definition sysfs.c:104
dentry_t * sysfs_dir_new(dentry_t *parent, const char *name, const inode_ops_t *inodeOps, void *private)
Create a new directory inside a mounted SysFS instance.
Definition sysfs.c:177
dentry_t * sysfs_file_new(dentry_t *parent, const char *name, const inode_ops_t *inodeOps, const file_ops_t *fileOps, void *private)
Create a new file inside a mounted SysFS instance.
Definition sysfs.c:216