Question: We are expected to do the following given OS161 code in a linux terminal with C programming. Thanks in advance for the help Assignment: b.
We are expected to do the following given OS161 code in a linux terminal with C programming. Thanks in advance for the help
Assignment:
b.
Implement a simplified system call void _exit(int exitCode) In OS161, you can end user programs by calling the _exit( ) system call. Without an implementation of _exit( ), the threads created to handle user programs will hang around forever, executing an infinite loop in the user space and taking up a lot of CPU time.
(HINT: You should find an existing function that is almost an ideal handler for the _exit( ) system call then modify that function to receive the exitCode as a parameter (you will also have to modify all the other uses of that function in order to pass the exitCode). In this part, you have to print out the exitCode that is passed. Once you implement the _exit() system call, you will find that useful for the next part to prevent infinite loop.
c.
You need to implement a system call int printint(int c) This system call should accept an integer and print it using the internal kprintf( ) function. The return value should be 0 if the integer is a multiple of 3 or 1 otherwise.
d.
You need to implement a system call int reversestring(const char *str, int len) This system call should accept a string and length of the string as input and print the reverse of the string using the internal kprintf( ) function. The return value should be 0 if the length of the string is multiple of 5 or 0 otherwise.
e.
Create a test program, named testprint, to test the printint( ) system call developed in Part C. Pass 5 integers (any) in a for loop and see if these are printed or not. (10 point)
f.
Create another test program, named testreverse to use the reversestring( ) system call developed in Part D. Pass any string as argument. Please note that you will need to use the _exit system call in the above programs to avoid infinite loop.
Note that the system calls given here are user-level functions, i.e. these are the functions that user programs will call to invoke the system calls. You will need to use different names for the handlers of these functions in the kernel (e.g., sys_reboot( ) is called to handle the reboot( ) system call.)
OS161 code:
/* * In-kernel menu and command dispatcher. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "opt-synchprobs.h" #include "opt-sfs.h" #include "opt-net.h" #define _PATH_SHELL "/bin/sh" #define MAXMENUARGS 16 void getinterval(time_t s1, u_int32_t ns1, time_t s2, u_int32_t ns2, time_t *rs, u_int32_t *rns) { if (ns2 < ns1) { ns2 += 1000000000; s2--; } *rns = ns2 - ns1; *rs = s2 - s1; } //////////////////////////////////////////////////////////// // // Command menu functions /* * Function for a thread that runs an arbitrary userlevel program by * name. * * Note: this cannot pass arguments to the program. You may wish to * change it so it can, because that will make testing much easier * in the future. * * It copies the program name because runprogram destroys the copy * it gets by passing it to vfs_open(). */ static void cmd_progthread(void *ptr, unsigned long nargs) { char **args = ptr; char progname[128]; int result; assert(nargs >= 1); if (nargs > 2) { kprintf("Warning: argument passing from menu not supported "); } /* Hope we fit. */ assert(strlen(args[0]) < sizeof(progname)); strcpy(progname, args[0]); result = runprogram(progname); if (result) { kprintf("Running program %s failed: %s ", args[0], strerror(result)); return; } /* NOTREACHED: runprogram only returns on error. */ } /* * Common code for cmd_prog and cmd_shell. * * This function uses the one_thread_only() function to make * the kernel menu thread wait until the newly-launched program * has finished. The one_thread_only() function is a bit ugly * (it works in this specific situation but not more generally) * Once you have A2 working, you should be able to use your * call your waitpid implementation (instead of one_thread_only()) * to provide the necessary synchronization. * * Also note that because the subprogram's thread uses the "args" * array and strings, there will be a race condition between the * subprogram and the menu input code if the menu thread is not * made to wait (using one_thread_only or some other mechanism) */ static int common_prog(int nargs, char **args) { int result; #if OPT_SYNCHPROBS kprintf("Warning: this probably won't work with a " "synchronization-problems kernel. "); #endif result = thread_fork(args[0] /* thread name */, args /* thread arg */, nargs /* thread arg */, cmd_progthread, NULL); if (result) { kprintf("thread_fork failed: %s ", strerror(result)); return result; } /* this function is a bit of a hack that is used to make * the kernel menu thread wait until the newly-forked * thread completes before the menu thread returns */ while (!one_thread_only()) { clocksleep(1); } return 0; } /* * Command for running an arbitrary userlevel program. */ static int cmd_prog(int nargs, char **args) { if (nargs < 2) { kprintf("Usage: p program [arguments] "); return EINVAL; } /* drop the leading "p" */ args++; nargs--; return common_prog(nargs, args); } /* * Command for starting the system shell. */ static int cmd_shell(int nargs, char **args) { (void)args; if (nargs != 1) { kprintf("Usage: s "); return EINVAL; } args[0] = (char *)_PATH_SHELL; return common_prog(nargs, args); } /* * Command for changing directory. */ static int cmd_chdir(int nargs, char **args) { if (nargs != 2) { kprintf("Usage: cd directory "); return EINVAL; } return vfs_chdir(args[1]); } /* * Command for printing the current directory. */ static int cmd_pwd(int nargs, char **args) { char buf[PATH_MAX+1]; struct uio ku; int result; (void)nargs; (void)args; mk_kuio(&ku, buf, sizeof(buf)-1, 0, UIO_READ); result = vfs_getcwd(&ku); if (result) { kprintf("vfs_getcwd failed (%s) ", strerror(result)); return result; } /* null terminate */ buf[sizeof(buf)-1-ku.uio_resid] = 0; /* print it */ kprintf("%s ", buf); return 0; } /* * Command for running sync. */ static int cmd_sync(int nargs, char **args) { (void)nargs; (void)args; vfs_sync(); return 0; } /* * Command for doing an intentional panic. */ static int cmd_panic(int nargs, char **args) { (void)nargs; (void)args; panic("User requested panic "); return 0; } /* * Command for shutting down. */ static int cmd_quit(int nargs, char **args, int exitstatus) { (void)nargs; (void)args; vfs_sync(); sys_reboot(RB_POWEROFF); thread_exit(); return 0; } /* * Command for mounting a filesystem. */ /* Table of mountable filesystem types. */ static const struct { const char *name; int (*func)(const char *device); } mounttable[] = { #if OPT_SFS { "sfs", sfs_mount }, #endif { NULL, NULL } }; static int cmd_mount(int nargs, char **args) { char *fstype; char *device; int i; if (nargs != 3) { kprintf("Usage: mount fstype device: "); return EINVAL; } fstype = args[1]; device = args[2]; /* Allow (but do not require) colon after device name */ if (device[strlen(device)-1]==':') { device[strlen(device)-1] = 0; } for (i=0; mounttable[i].name; i++) { if (!strcmp(mounttable[i].name, fstype)) { return mounttable[i].func(device); } } kprintf("Unknown filesystem type %s ", fstype); return EINVAL; } static int cmd_unmount(int nargs, char **args) { char *device; if (nargs != 2) { kprintf("Usage: unmount device: "); return EINVAL; } device = args[1]; /* Allow (but do not require) colon after device name */ if (device[strlen(device)-1]==':') { device[strlen(device)-1] = 0; } return vfs_unmount(device); } /* * Command to set the "boot fs". * * The boot filesystem is the one that pathnames like /bin/sh with * leading slashes refer to. * * The default bootfs is "emu0". */ static int cmd_bootfs(int nargs, char **args) { char *device; if (nargs != 2) { kprintf("Usage: bootfs device "); return EINVAL; } device = args[1]; /* Allow (but do not require) colon after device name */ if (device[strlen(device)-1]==':') { device[strlen(device)-1] = 0; } return vfs_setbootfs(device); } static int cmd_kheapstats(int nargs, char **args) { (void)nargs; (void)args; kheap_printstats(); return 0; } //////////////////////////////////////// // // Menus. static void showmenu(const char *name, const char *x[]) { int ct, half, i; kprintf(" "); kprintf("%s ", name); for (i=ct=0; x[i]; i++) { ct++; } half = (ct+1)/2; for (i=0; i= MAXMENUARGS) { kprintf("Command line has too many words "); return E2BIG; } args[nargs++] = word; } if (nargs==0) { return 0; } for (i=0; cmdtable[i].name; i++) { if (*cmdtable[i].name && !strcmp(args[0], cmdtable[i].name)) { assert(cmdtable[i].func!=NULL); gettime(&beforesecs, &beforensecs); result = cmdtable[i].func(nargs, args); gettime(&aftersecs, &afternsecs); getinterval(beforesecs, beforensecs, aftersecs, afternsecs, &secs, &nsecs); kprintf("Operation took %lu.%09lu seconds ", (unsigned long) secs, (unsigned long) nsecs); return result; } } kprintf("%s: Command not found ", args[0]); return EINVAL; } /* * Evaluate a command line that may contain multiple semicolon-delimited * commands. * * If "isargs" is set, we're doing command-line processing; print the * comamnds as we execute them and panic if the command is invalid or fails. */ static void menu_execute(char *line, int isargs) { char *command; char *context; int result; for (command = strtok_r(line, ";", &context); command != NULL; command = strtok_r(NULL, ";", &context)) { if (isargs) { kprintf("OS/161 kernel: %s ", command); } result = cmd_dispatch(command); if (result) { kprintf("Menu command failed: %s ", strerror(result)); if (isargs) { panic("Failure processing kernel arguments "); } } } } /* * Command menu main loop. * * First, handle arguments passed on the kernel's command line from * the bootloader. Then loop prompting for commands. * * The line passed in from the bootloader is treated as if it had been * typed at the prompt. Semicolons separate commands; spaces and tabs * separate words (command names and arguments). * * So, for instance, to mount an SFS on lhd0 and make it the boot * filesystem, and then boot directly into the shell, one would use * the kernel command line * * "mount sfs lhd0; bootfs lhd0; s" */ void menu(char *args) { char buf[64]; menu_execute(args, 1); while (1) { kprintf("OS/161 kernel [? for menu]: "); kgets(buf, sizeof(buf)); menu_execute(buf, 0); } }