10 Feb 2017: Part 1: OS/161 Updates

(This is the first part of a two-part announcement. Please reply to this thread if you have any problems with the merge.)

We’re about to push our first set of updates to the base OS/161 sources. You will need these before you can submit ASST1. These changes bring our base OS/161 sources up to OS/161 version 2.0.3, which David release recently.

Unfortunately, there is a fairly good probability that these changes will cause merge conflicts if you have started ASST1. They introduce a new deadlock detector into the kernel which requires changes to your locks. So please be careful as you perform this merge. The change is fairly minor, and feel free to ask for help. Note that the deadlock detection code should be added inside of the critical section inside of lock_acquire and lock_release.

Assuming you have our OS/161 GitHub repository set up as your staff remote, here is what to do. First, make sure that all of your changes are committed and pushed before proceeding. Then:

git pull staff master
git status

When the git pull completes, either one of two things will have happened. Both git pull and the following git status

  • The merge will have been completed successfully without causing any conflicts.
  • The merge will have created conflicts for you to address.

Even if the merge does not create conflicts I would strongly suggest that you review the files that were changed. Git’s merging algorithms are good, but not perfect. You should probably examine any changes to files that you may have edited. Changes to files that you don’t know or care about can usually be safely ignored.

Merge conflicts happen when Git detects overlapping changes to the same files. When this happens, you’ll find this kind of content in the files that are conflicted:

One set of changes
The other set of of changes.

Your job is to combine both sets of changes and remove the conflict markers. Once that’s done, you can use git add <filename> to tell Git that you are done with the file. Once you have successfully addressed all conflicts, use git commit to finish the merge commit and you are done.

Also note that you need to successfully merge these changes and update test161 to version 1.3.0 (see the next part of this post) before you can submit your solutions. Happily, updating test161 is simple.

If you have trouble, please reply to this thread. I’ll be online periodically this weekend to help, and will ask other staff members to monitor the forum as well.

I have not updated but my partner did, and now his kernel will not compile. it is missing opt-hangman.h, which is included in spinlock.h, says no such file.

Reconfigure the kernel starting with ./config DUMBVM (or whatever), rebuild the dependencies, and try compiling again.

I’ve noticed that several groups are having trouble with the merge. This is because, rather than using git clone and adding their private repository as a remote, they decided to create a new repository using git init and then copy our OS/161 source tree into the new repository.

Do not do this. The only time you should ever use git init is when you are starting a brand new repository for a project that nobody has ever worked on before (or that misguided people were working on using some sad old VCS system like CVS or SVN). If you have a Git repository as a starting point, always do a git clone and start from there. Always.

Why? Well one reason is so you can receive upstream changes—like the ones that we just pushed. You can find lots of details about Git online, but when you clone a repository you get not only the files but also the entire revision history of the repository that you cloned. That history gets used when you merge.

Git organizes all of your commits into a directed acyclic graph (DAG). (Usually repositories contain only one graph with a single root, but that’s not always true.) Let’s say that you created a new repository and made four separate commits to master. Your commit graph might look like this:

A -> B -> C -> D

You can use Git commands to compare your repository across different commits—which is itself pretty useful. You can also revert commits, which undoes just the changes from that commit—also very useful. But where this history really comes in handy is when you have to do merges.

For example, let’s say that our OS/161 repository looked like the one above when you cloned it. Then you go on and make some other changes, at which point your revision history looks like this:

A -> B -> C -> D -> E -> F

You added commits E and F which contain your changes. But, at the same time, I go on and make other changes to the same repository. So my history looks like this:

A -> B -> C -> D -> G -> H

I added commits G and H which contain my changes. When you try to merge my branch into yours, what Git tries to do is find a common ancestor so that it can determine which commits your repository is missing. In the example above, if you try to merge my branch Git determines that D is the common ancestor, and so you are missing commits G and H from my branch. It then tries to apply those changes to the tip of your current branch and creates a new commit that indicates that your branch now includes those changes. The Git merge documentation has a nice graph of what your branch will look like next.

But all this is predicated on Git being able to find a common ancestor. If you create a new repository and copy your file in and then run git init, your history will look like this:

Z -> G -> H

(Keep in mind that the way that Git identifies commits includes the timestamp that the commit was made. So even if you commit the exact same files at a different time into a different repository, the commit hashes will be different and Git will consider them to be different when merging.)

At this point there will be no way to merge changes from our branch, since there is no longer a common ancestor. And you’re in trouble.

If your merge isn’t working, one way to be sure that you are having this problem is to run git log. If you don’t have entries back to 2015, then you don’t have a clone of our repository.

There are a few ways to fix this:

  1. Clone a new copy of our repository. Manually merge changes from your current repository into the new repository. Happily these are probably confined to just a few files at this point: synch.c, synch.h, etc. Once you are done, commit, add your private repository as a remote (you may want to create a new private repository for this purpose), and then push. This is probably the simplest option at this point, but you never want to do this again: particularly when you have a larger and more complex set of changes. Imagine that one tree has some changes that you want but so does another tree, and you aren’t sure where they are. A mess.
  2. Clone a new copy of our repository. Check out commit 93cc12e3—which is where you should have started at the beginning of the semester. At this point you will be in detached head mode, so create a branch to save your changes. Copy over all of your files (except stuff in .git) into the new repository, overwriting any and all files in there. Commit your changes to the new branch. Then merge in master. When you are done, you can switch to master, merge in your new branch, and then delete the new branch. Again: at this point add your private repository as a remote and push to

Both these options are not things that you ever want to do again. So if you found yourself in this position, let me repeat myself: do not do this again. You should never use git init for this class for the rest of the semester. If you find yourself having problems with the repository you cloned, post on the forum or come to office hours for help.

1 Like