Вы находитесь на странице: 1из 3

Lab 4- Concurrency and Locks

Katherine Bau
kb577
Kevin Gao
kg349

Lab Overview:
Our task for lab 4 was to modify the process concurrency system that we implemented in lab 3
by adding features to handle locks. The primary focus of this lab was implementing the main
lock functions, as well as adjusting the process_select function to check for the blocking status of
processes.

The Functions:
Functionality wise, there wasnt as much to do as last time. The first thing we did was modify the
process_state, aka the process_t, struct from the previous lab. In this lab, process_t now has a
blocked field that tells us if a particular process has been blocked or not. The idea behind
blocking when using locks is that to ensure safety and fairness in the program, we can only allow
one process into the critical section at a time. That process will obtain a lock, which locks the
current process and blocks all the other processes in order to keep them from executing. When
the current process finishes, it releases the lock, or unlocks itself, allowing the other processes
to become unblocked, and the program continues with the next process.

Implementing l_init was fairly simple. A call to l_init requires an input of a lock_t argument, and
l_init initializes the lock structure by setting the blocked_processses field (explained later) to
NULL, which is equivalent to 0, and setting the free field to 1.

Implementing l_lock required that we temporarily disable interrupts by changing the value of
PIT->CHANNEL[0].TCTRL. In l_lock, the function checks if the lock_t object is not free, i.e, it
checks if l->free is NULL. If it is, the the current_processs blocked field gets changed to a 1,
and we add the current_process to the lock_t objects list of blocked_processes, i.e, the current
process is added to l->blocked_processes. Finally, the function calls process_blocked, and then l-
>free is changed to a 0 to indicate that the lock_t object is no longer free. L_lock then re-enables
interrupts.

Implementing l_unlock is slightly more complicated. First, l_unlock creates a new process_t
object called unblocked. This is the object that will hold the pointer to the first process that might
be waiting to obtain the lock. Interrupts are then temporarily disabled, and the function will now
check if the lock_t object currently has any blocked_processes, i.e, the function checks if l-
>blocked_processes != NULL. If it is, then l_unlock will call process_queue_pop to remove the
first process from the list of blocked processes and stores the process into unblocked, and then it
unblocks the process (unblocked->blocked is set to 0). Unblocked is then added to the
process_queue. If there are no blocked processes, l_unlock will free the lock. Interrupts are then
re-enabled.

As far as the previous functions (process_create, process_start, and process_select) the only
function that needed to be modified was process_select and process_create. For process_create,
we needed to initialize the extra fields that we added to process_t. For process_select, we needed
to add extra features to account for blocked processes. The new features meant that executions
such as remove and add now happen atomically. Process_select now also checks to see if either
both the process_queue is NULL and the cursp is NULL, or if the process_queue is NULL and
the current process is blocked. If either of these cases are true, then the current_process is set to
NULL, and the function returns NULL.

Important Data Structures:

Following from the last lab, we kept the original process_queue data structure. As a quick recap,
process_t keeps track of the stack pointer, the next process_state, the original stack pointer and
the original size. We added a blocked field to the data structure so that now process_t objects
can keep track of whether or not they are blocked (0 if it is not blocked, 1 if it is blocked).

There is a new C struct in our code: the lock_state struct, aka the lock_t. Lock_t has 2 different
fields; a process_t field called blocked_processes, which is used to hold the list of processes that
have been blocked as a result of another process acquiring the lock, and a free field, which lets
the program know if a certain lock_t object is free or not (0 if it is not free, 1 if it is). Each of the
lock.c functions takes in a lock_t object as an argument. Lock_t and process_t are both defined in
our shared_structs.h file.

Other than the aforementioned changes, our linked list data structure (process_queue) hasnt
changed much. We kept the two original helper functions, process_queue_add and
process_queue_rem, and we also added another helper function process_queue_pop, which is
simply a non-void version of process_queue_rem; i.e, it returns a process_t structure as the
output.
Process Queue

current_proce next

new_process_ next

new_process_ next

(The process queue is a simpler visualization of how each process is stored in its own separate
stack, as shown in the heap. All the information about each process is stored to each different
stack, and the stack pointer information is kept inside the process_t object, which resembles the
PCB system)

Testing the implementations:

To test our code, we used the given test case files, as well as the two files that we wrote
ourselves. We were able to change the test files given to us to test different relevant cases. For
example, we changed one of the test cases to have only one process and lock so we could check
that our lock works with only one process. Then we also checked the locks by changing the order
of the read and write, so that we expected the reads to be executed at the same time, and then the
write to execute. To test the conditionals we tested three readers and expected it to act like only
one reader, because reads can go on at the same time. Then we tested three writers, and since
they cannot write at the same time we expected it to toggle 6 times.

Work Distribution: the work distribution was divided into two different groups. Katherine
worked mostly on the process functionality and the test cases, while Kevin worked mostly on the
lock implementation and modifying the data structures.

Вам также может понравиться