Owen Sullivan User Mode Thread Library: * DESCRIPTION: This library re-implements user threads and Mutex locks using custom data structures (including a linked list) and the getcontext, makecontext, and swapcontext functions. It becomes a static library that can be compiled into an existing program. * KNOWN PROBLEMS: ** Currently, threads are not actually executed concurrently. Rather, they're scheduled one after the other. This may cause the return values of threads not to be accurate in some cases, and it may also cause threads to hang occasionally. *** This may also be causing preemptive scheduling at intervals under 100us to not work correctly, but I'm not 100% sure the issues are related. I'm able to get it working once in a blue moon, but hardly consistently enough that I'd get lucky with the system clock on the autograder. *** I am extremely confident that the issue has something to do with the way I'm getting context in threadInit. In the current implementation (i.e., what I submitted to get a "good enough" grade after literally days of non-stop testing), threadYield is not properly switching back to the main thread because it's better that threadYield not switch correctly than the whole program be derailed by trying to make it work. Ideally, it should actually switch between threads. * DESIGN: ** mythreads.c, which compiles into libmythreads.a, uses a linked list of nodes comprised of homemade thread control blocks to schedule threads with a FIFO discipline. The linked list itself only links forward (using a pointer to the next node). ** mythreads.c also contains a structure of locks, meant to imitate Mutex locks, of size NUM_LOCKS. Each lock has a set of condition variables of size CONDITIONS_PER_LOCK. ** mythreads.c contains a custom few helper functions: *** thFuncWrapper, which takes a function pointer (thFuncPtr) and an argument for that function pointer as arguments and stores the return value of the call to thFuncPtr before passing it to threadExit. Reference: https://stackoverflow.com/a/65776559 *** getThreadByID, which traverses through the linked list of thread nodes and either finds the one with a matching ID or returns NULL if no match is found. The NULL return exists for error checking in threadJoin, so that the main thread is not terminated early. *** checkIfLocked, which is a simple spin lock implementation that mimics mutex locks.