Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

COMP 3000 (WINTER 2023) OPERATING SYSTEMS

ASSIGNMENT 1 --- SOLUTIONS

Questions part 1 [6]

The sudo command is a convenient way of executing commands as the root user (by default, unless another user is specified) if the current user is allowed to (by   /etc/sudoers). Now, answer the following questions.

1.  [2] To set an environment variable, you can “export MYVAR=99”, then you will be able to see it using the command env”. But if you sudo env” (running env as the root user) you won’t see it. Why        [1/2]? What simple argument can you add to sudo env” to see MYVAR=99” [1/2]?

The internal command export only tells the shell to make the environment variable available to subsequently executed commands (by passing them to child processes). This is still under the same user. The sudo command (external) actually acts as a login program (similar to 3000userlogin, which you will see later) to temporarily switch to another user where the environment of the invoking user is not preserved by default. sudo -E env will preserve the environment variables. (man sudo)

2.  [2] You have just learned the concepts of user/kernel modes (hardware-enforced) and root/non-root users (OS-enforced), which are orthogonal to each other. Briefly describe when different mode-user combinations happen during the execution of “ sudo env”. As an example of one combination, when it is doing X, it runs in kernel mode as the regular user (e.g., student).

With the two aspects being orthogonal in mind, just logically analyze what the sudo env command does and what operations are involved. In particular, at the very beginning, it must be running as the current regular user (e.g., student) in the user mode. Then, whenever theres any access to the outside (of the OS containment), such as prompting for the student users password, it must make system calls which are handled in the kernel mode. So, at this time, it runs as the regular user in the kernel mode. Next, once authenticated, it will switch to the user root, running as the root user in the user mode. Later, (for multiple times) it also needs to make system calls to access outside resources, e.g., printing the many lines of environment variables to the terminal, hence running as the root user in the kernel mode. The order does NOT matter (as they can be highly interleaved and involved many times).

3.  [1] Explain why “ sudo echo $MYVAR” works as is, without the fix above in question 1?

The resolution of the environment variable $MYVAR happens when the shell parses the string before passing it to the command (in this case, sudo”), hence not affected by sudo not preserving the environment by default (no need for the -E”) as it has not been started.

4.  [1] Why does “ sudo export MYVAR=99” fail?

export is an internal command, i.e., sudo expects a program binary file it can run but theres no file named export”, hence the error. Optional thinking: When export is issued as a command the shell understands it as an internal command, in contrast, when it is put after sudo”, the shell passes everything following sudo as its arguments without trying to understand them.

Questions part 2 [7]

The following questions (where applicable) will be based on the original 3000memview.cin Tutorial 2:

5.  When you change each malloc() call to allocate more than 128KiB, you may have noticed (or will   notice) that malloc() switches between the system calls mmap() and brk() for memory allocation  depending on a preset threshold (which in this case by default is 128KiB). With the help of man mallopt, answer the following questions. Note that this trains you to be able to search for a solution by skimming through available documentation (so no need to read it word by word).

a. [2] What are the two ways to change this threshold? Be specific.

1. Making a function call to mallopt(), passing the argument M_MMAP_THRESHOLD.

2. Changing the environment variable MALLOC_MMAP_THRESHOLD_.

b. [2] To change this threshold to 200KiB (i.e., 200 x 1024) using one of the two ways, provide

the command(s) as your answer.

export MALLOC_MMAP_THRESHOLD_=204800

c. [3] Modify 3000memview.c to implement the other way. Your code must compile. Very simple: just add this line before the loop: mallopt(M_MMAP_THRESHOLD, 204800);

For both b and c, you (or the TA) should be able to verify the threshold change by replacing malloc(4096) with malloc(199*1024) and malloc(200*1024) respectively in your 3000memview.c, and watch the strace output.

Questions part 3 [7]

The following questions (where applicable) will be based on the originalhello.c in

Tutorial 1, syscall-hello.c in Tutorial 2, and this newsyscall2-hello.c. Compile and run them.

6.  All the three programs do the same thing, i.e., print Hello world!” as the output. But speaking of portability (as we discussed in class), they are different.

a. [2] Order the three programs from the least portable to the most portable (just list them in

order as your answer).

syscall2-hello.c -> syscall-hello.c -> hello.c

b. [3] Explain why you ordered them this way (again, be specific for each program).

hello.c: it makes a library call printf() in the standard C library, corresponding to a higher level of abstraction. It is the most portable because printf() is available wherever theres the standard C library, e.g., even on Windows.

This provides cross-OS portability.

syscall-hello.c: it makes a system call write() but via a C wrapper syscall(). Not to mention whether syscall() will be available, the system call write() may not be available on another OS (e.g., non-Linux). But at least it hides how the system call is actually made (e.g., x86 vs. ARM).

This provides cross-architecture portability.

syscall2-hello.c: it directly makes the system call write() via the machine instruction syscall”. This means if a CPU architecture does not have the syscall instruction (e.g., ARM uses SVC), it will not work.

No exact wording is expected but roughly the same idea.

7.  [2] What is the key difference between syscall-hello.c and syscall2-hello.c, in terms of types of calls made for the same purpose? Without relying on any assembly knowledge, how do you know? (using only commands we have used so far)

Difference: syscall-hello.c makes library calls (the C wrapper) which eventually will make system calls. syscall2-hello.c makes system calls directly without involving any library calls.

How do you know: ltrace will show that syscall2-hello.c makes no library calls.

Note: as discussed in the tutorials, if you do not use the -z lazy”, the default will be -z now which means the symbol resolution is done at load time and ltrace will not see any library calls for either one.