This commit is contained in:
Alexander Krause 2023-09-22 11:19:29 +02:00
commit 5bfe56aafd
15 changed files with 572 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.build*
.solution

32
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,32 @@
# This is a configuration file for GitLab Continuous Integration (CI).
#
# At each "push", GitLab will use this file (named '.gitlab-ci.yml') to start
# a docker container with the image of a Linux distribution (in this case
# Ubuntu Focal) with an already installed build tool chain and compile the
# source in the git repository.
# The status (indicated by the exit code of 'make') is clearly visible on the
# project page of your repository in GitLab:
# If a commit contains an invalid (untranslatable) state, an error (red 'x')
# is displayed and the author is notified by mail.
#
# Please note: This will only test the build of your operating system,
# but not the [correct] functionality!
#
#Further information: https://docs.gitlab.com/ee/ci/
GCC-Build:
image: inf4/stubs:gcc-x64
script:
- if [ -f Makefile ] ; then make clean ; make ; fi
# Optional: Use Clang 11
#Clang-Build:
# image: inf4/stubs:clang-x64
# script:
# - make clean ; make CXX=clang++-11
# Check style guide using cpplint
linter:
image: inf4/stubs:cpplint
script:
- if [ -f Makefile ] ; then make clean ; make lint ; fi

16
CPPLINT.cfg Normal file
View File

@ -0,0 +1,16 @@
# StuBS Coding Style Checker
#
# Wir orientieren uns grob an den Google C++ Style Guide ( http://google.github.io/styleguide/cppguide.html )
# mit primär folgenden Änderungen/Anpassungen:
#
# - Tabs statt Leerzeichen. Spart Bytes ;)
# - Zeilenlänge ist 120
# - Keine Angaben zum Copyright
# - Aufgrund des Aufgabenbuildsystems sind neue / leere Zeilen leider nicht immer vermeidbar
#
# Zum Prüfen empfiehlt sich beispielsweise das Pythonscript CPPLINT.py ( https://github.com/cpplint/cpplint )
# welches mit dieser Konfigurationsdatei arbeiten kann.
#
set noparent
filter=-whitespace/tab,-legal/copyright,-runtime/int,-runtime/threadsafe_fn,-readability/todo,-build/include_subdir,-runtime/references,-build/include_what_you_use,-whitespace/blank_line
linelength=120

10
LICENSE Normal file
View File

@ -0,0 +1,10 @@
Copyright 1998-2002 Institut für Verteilte Systeme (IVS), Otto-von-Guericke-Universität Magdeburg
Copyright 2002-2022 Lehrstuhl für Informatik 4, Friedrich-Alexander-Universität Erlangen-Nürnberg
Diese Vorlage dient als Grundlage für Lehrveranstaltungen und darf nicht ohne vorherige, schriftliche Erlaubnis der Urheberrechtsinhaber veröffentlicht oder weitergegeben werden.
Es ist erlaubt und wünschenswert, diese Vorlage als Inspiration für eigene Projekte zu verwenden, es wird allerdings erbeten, dass die Vorgabe nicht mit deiner Lösung veröffentlicht wird.
Wir, als Lehrende, möchten alle teilnehmenden Studierenden dazu ermutigen eine eigene Lösung zu erstellen; eine veröffentlichte Lösung ist ein Anreiz zum Abschreiben, den wir gerne vermeiden möchten.
This skeleton is provided as a foundation for educational purposes and therefore MUST NOT BE DISTRIBUTED OR PUBLISHED without prior, written consent of the copyright holders.
You are free to use this skeleton as inspiration for your projects, but, please, do not publish it along with your solution.
We, as lecturers, want to encourage every participating student to write a solution themself; a public solution is an allurement to copying we want to avoid.

42
README.md Normal file
View File

@ -0,0 +1,42 @@
MPStuBS - Multiprozessor Studenten Betriebssystem
=================================================
Coding Guidelines
-----------------
Similar to [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) but with following exceptions:
- No license boilerplate
- *Tabs* instead of *Spaces*
- Line length of 120 characters
- `#pragma once` instead of `#include` guards
The code should be *self-documenting*, don't state the obvious!
However, this does not make comments superfluous:
Since good naming is sometimes not enough, more advanced parts need to be documented,
so any operating system developer should be able to easily understand your code.
### Naming Convention
- **Variables**: lowercase with underscore
char* variable_name;
- **Constants** (and **enum** values): uppercase with underscore
const int CONST_VALUE = 42;
- **Type Names** (`class`/`struct`/`namespace`/`enum`): Capital letter, camel case
class SomeClassName;
- **Methods/Functions** (C++): start with lowercase letter, then camel case
void someFunctionName();
- **extern "C" Functions**: lowercase with underscore (like variables).
void interrupt_handler(int vector);
- **File Names**: lowercase, main type name, underscores only if is a sub type
folder/classname.cc

1
object/outputstream.cc Normal file
View File

@ -0,0 +1 @@
#include "outputstream.h"

237
object/outputstream.h Normal file
View File

@ -0,0 +1,237 @@
/*! \file
* \brief This file contains the \ref OutputStream
*
* Along with the class OutputStream itself, this file contains definitions for the
* manipulators \ref hex, \ref dec, \ref oct, and \ref bin, which are used for
* changing the radix, and \ref endl for signaling the end of the current line.
* \ingroup io
*
* \par Manipulators
* To simplify formatting text and numbers using the class OutputStream, we define
* so-called manipulators.
* For example, the expression
* <tt>kout << "a = " << dec << a << " is hexadecimal " << hex << a << endl;</tt>
* should, at first, print the value stored in decimal and then in hexadecimal
* form, followed by a line break.
* The intended properties can be realized by implementing \ref hex, \ref dec, \ref oct, \ref bin,
* and \ref endl as functions (i.e., they are, in particular, not methods of \ref OutputStream)
* that take (as first parameter) and return a reference to an OutputStream object.
* When compiling the expression show above, the method
* <tt>OutputStream& OutputStream::operator<< ((*f*) (OutputStream&))</tt>
* is chosen when one of the functions \ref hex, \ref dec, \ref oct, \ref bin, or \ref endl
* is streamed an \ref OutputStream, which finally will execute the passed function.
*
* \note The term manipulator originates from the book
* [The C++ Programming Language](http://www.stroustrup.com/4th.html)
* by Bjarne Stroustrup. Refer to this book for further explanations.
*/
#pragma once
#include "stringbuffer.h"
/*! \brief The class OutputStream corresponds, essentially, to the class ostream
* from the C++ IO-Stream library.
*
* As relying on the method \ref Stringbuffer::put() is quite cumbersome when
* not only printing single characters, but numbers and whole strings, the
* class OutputStream provides a convenient way of composing output of variables of
* varying data types.
* Therefore, OutputStream implements shift operators `operator<<`` for various
* data types (similar to those known from the C++ IO-Stream library)
*
* For further convenience, OutputStream also allows printing integral numbers in
* decimal, binary, octal, and hexadecimal format.
* Remember that, for negative numbers, the sign is only printed when using the
* decimal number system; for binary, octal, and hex, the number is printed as
* stored in the machine word without interpreting the sign.
* For Intel CPUs, two's complement is used for storing negative values, `-1`,
* for example, will print hex `FFFFFFFF` and octal `37777777777`.
*
* OutputStream's public methods/operators all return a reference to the object
* they are called on (i.e. `*this`). Returning `*this` allows chaining those
* stream operators in a single expression, such as
* <tt>kout << "a = " << a</tt>;
*
* At this point in time, OutputStream implements `operator<<` for chars, strings
* and whole numbers. An additional `operator<<` allows using manipulators
* whose detailed description is given below.
*/
class OutputStream {
OutputStream(const OutputStream&) = delete;
OutputStream& operator=(const OutputStream&) = delete;
public:
/*! \brief Number system used for printing integral numbers (one of 2,
* 8, 10, or 16)
*/
int base;
/*! \brief Default constructor. Initial number system is decimal.
*
* \todo Implement Constructor
*
*/
OutputStream() {}
/*! \brief Destructor
*/
virtual ~OutputStream() {}
/*! \brief Clears the buffer.
*
* Pure virtual method that must be implemented by derived
* (non-abstract) classes.
* Formatting of the buffer contents can be implemented differently by
* different derived classes
*/
virtual void flush() = 0;
/*! \brief Print a single character
*
* \todo Implement Operator
*
* \param c Character to be printed
* \return Reference to OutputStream os; allows operator chaining.
*/
OutputStream& operator << (char c);
/*! \brief Print a single character
* \note In C, there are no "characters" in that sense, but only
* integers. A `char`, therefore, is a 8 bit number with the most
* significant bit (optionally) representing a sign.
* Depending on whether signed or not, the value ranges are [-128, 127]
* or [0; 255]. For GCC, a `char` is a `signed char`.
*
* \todo Implement Operator
*
* \param c Character to be printed
* \return Reference to OutputStream os; allows operator chaining.
*/
OutputStream& operator << (unsigned char c);
/*! \brief Printing a null-terminated string
*
* \todo Implement Operator
*
* \param string String to be printed
* \return Reference to OutputStream os; allows operator chaining.
*/
OutputStream& operator << (const char* string);
/*! \brief Print a boolean value
*
* \todo Implement Operator
*
* \param b Boolean to be printed
* \return Reference to OutputStream os; allows operator chaining.
*/
OutputStream& operator << (bool b);
/*! \brief Print an integral number in radix `base`
*
* \todo Implement Operator
*
* \param ival Number to be printed
* \return Reference to OutputStream os; allows operator chaining.
*/
OutputStream& operator << (short ival);
/// \copydoc OutputStream::operator<<(short)
OutputStream& operator << (unsigned short ival);
/// \copydoc OutputStream::operator<<(short)
OutputStream& operator << (int ival);
/// \copydoc OutputStream::operator<<(short)
OutputStream& operator << (unsigned int ival);
/// \copydoc OutputStream::operator<<(short)
OutputStream& operator << (long ival);
/// \copydoc OutputStream::operator<<(short)
OutputStream& operator << (unsigned long ival);
/// \copydoc OutputStream::operator<<(short)
OutputStream& operator << (long long ival);
/// \copydoc OutputStream::operator<<(short)
OutputStream& operator << (unsigned long long ival);
/*! \brief Print a pointer as hexadecimal number
*
* \todo Implement Operator
*
* \param ptr Pointer to be printed
* \return Reference to OutputStream os; allows operator chaining.
*/
OutputStream& operator << (const void* ptr);
/*! \brief Calls one of the manipulator functions.
*
* Method that calls the manipulator functions defined below, which
* allow modifying the stream's behavior by, for instance, changing the
* number system.
*
* \todo Implement Operator
*
* \param f Manipulator function to be called
* \return Reference to OutputStream os; allows operator chaining.
*/
OutputStream& operator << (OutputStream& (*f) (OutputStream&));
};
/*! \brief Enforces a buffer flush.
*
* \todo Implement Manipulator
*
* \param os Reference to stream to be flushed.
* \return Reference to OutputStream os; allows operator chaining.
*/
OutputStream& flush(OutputStream& os);
/*! \brief Prints a newline character to the stream and issues a buffer flush.
*
* \todo Implement Manipulator
*
* \param os Reference to stream to be modified.
* \return Reference to OutputStream os; allows operator chaining.
*/
OutputStream& endl(OutputStream& os);
/*! \brief Print subsequent numbers in binary form.
*
* \todo Implement Manipulator
*
* \param os Reference to stream to be modified.
* \return Reference to OutputStream os; allows operator chaining.
*/
OutputStream& bin(OutputStream& os);
/*! \brief Print subsequent numbers in octal form.
*
* \todo Implement Manipulator
*
* \param os Reference to stream to be modified.
* \return Reference to OutputStream os; allows operator chaining.
*/
OutputStream& oct(OutputStream& os);
/*! \brief Print subsequent numbers in decimal form.
*
* \todo Implement Manipulator
*
* \param os Reference to stream to be modified.
* \return Reference to OutputStream os; allows operator chaining.
*/
OutputStream& dec(OutputStream& os);
/*! \brief Print subsequent numbers in hex form.
*
* \todo Implement Manipulator
*
* \param os Reference to stream to be modified.
* \return Reference to OutputStream os; allows operator chaining.
*/
OutputStream& hex(OutputStream& os);

2
object/stringbuffer.cc Normal file
View File

@ -0,0 +1,2 @@
#include "stringbuffer.h"

76
object/stringbuffer.h Normal file
View File

@ -0,0 +1,76 @@
/*! \file
* \brief \ref Stringbuffer composes single characters into a buffer
*/
#pragma once
/*! \brief The class Stringbuffer composes single characters into a longer text that can be processed on block.
*
* To make Stringbuffer as versatile as possible, the class does make
* assumptions about neither the underlying hardware, nor the meaning of
* "processing". When flush() is called (i.e., either on explicit request or
* once the buffer is full). To be hardware independent, flush() is to be
* implemented by the derived classes.
*
* \par Hints for Implementation
* Use a buffer of fixed size for caching characters, which should be
* accessible by derived classes.
* Keep in mind that the derived implementation of flush() will need to know
* about numbers of characters in the buffer.
*
* \par Notes
* Reason for the existence of this class is that generating longer texts is
* often implemented by assembly of small fragments (such as single characters
* or numbers).
* However, writing such small fragments directly to (for example) screen is
* quite inefficient (e.g., due to the use of IO ports, syscalls, or locks) and
* can be improved drastically by delaying the output step until the assembly
* is finished (or the buffer runs full).
*/
class Stringbuffer {
// Prevent copies and assignments
Stringbuffer(const Stringbuffer&) = delete;
Stringbuffer& operator=(const Stringbuffer&) = delete;
// All variables and methods are protected in this class,
// as the derived classes need direct access to be buffer,
// the constructor, the destructor, and the method put.
// flush() is to be implemented either way and may be redefined
// as public.
protected:
/// buffer containing characters that will be printed upon flush()
char buffer[80];
/// current position in the buffer
long unsigned pos;
/*! \brief Constructor; Marks the buffer as empty
*
* \todo Complete Constructor
*/
Stringbuffer() { }
/*! \brief Inserts a character into the buffer.
*
* Once the buffer is full, a call to flush() will be issued and
* thereby clearing the buffer.
*
* \todo Implement Method
*
* \param c Char to be added
*/
void put(char c);
/*! \brief Flush the buffer contents
*
* This method is to be defined in derived classes, as only those know
* how to print characters.
* flush() is required to reset the position pos.
*/
virtual void flush() = 0;
public:
/*! \brief Destructor (nothing to do here)
*/
virtual ~Stringbuffer() { }
};

22
test-stream/Makefile Normal file
View File

@ -0,0 +1,22 @@
VERBOSE = @
OBJDIR = build
CXX = g++
MKDIR = mkdir
CC_SOURCES = ../test-stream/console_out.cc ../test-stream/test.cc ../test-stream/file_out.cc ../object/outputstream.cc ../object/stringbuffer.cc
CXXFLAGS = -std=c++11 -m64 -I../object -I.
TARGET = $(OBJDIR)/test
all: run
run: $(TARGET)
@./$<
$(TARGET): $(CC_SOURCES)
$(VERBOSE) $(MKDIR) -p $(OBJDIR)
$(VERBOSE) $(CXX) -o $@ $(CXXFLAGS) $^
clean:
@echo "RM $(OBJDIR)"
$(VERBOSE) rm -rf $(OBJDIR)
.PHONY: all run clean

View File

@ -0,0 +1,2 @@
#include "console_out.h"

33
test-stream/console_out.h Normal file
View File

@ -0,0 +1,33 @@
/*! \file
* \brief \ref ConsoleOut "Console" \ref OutputStream "output" (for the voluntary C++ exercise only)
*/
#pragma once
#include "outputstream.h"
/*! \brief Write text on console (`STDOUT`)
*
* This class allows writing to the console similar to `std::cout` from the standard C++ library.
* The class is derived from \ref OutputStream.
*/
class ConsoleOut : public OutputStream {
// Prevent copies and assignments
ConsoleOut(const ConsoleOut&) = delete;
ConsoleOut& operator=(const ConsoleOut&) = delete;
public:
/*! \brief Constructor
*
* \todo Implement constructor
*/
ConsoleOut();
/*! \brief Output the string on the screen.
*
* The implementation should solely use `putchar()`
*
* \todo Implement virtual method
*/
virtual void flush() override; //NOLINT
};

2
test-stream/file_out.cc Normal file
View File

@ -0,0 +1,2 @@
#include "file_out.h"

59
test-stream/file_out.h Normal file
View File

@ -0,0 +1,59 @@
/*! \file
* \brief \ref FileOut "File" \ref OutputStream "output" (for the voluntary C++ exercise only)
*/
#pragma once
#include "outputstream.h"
/*! \brief Write text into file
*
* This class allows a comfortable output to a file only by using the elementary
* system calls `open()` / `write()` / `close()` and (optional) `fsync()`.
* The class is derived from \ref OutputStream.
*/
class FileOut : public OutputStream {
// TODO: Add (private) attributes, if required
public:
/*! \brief Constructor
*
* Opens the file for writing using the system call `open()`.
* \param path Path to the output file
*
* \todo Implement constructor
*/
explicit FileOut(const char * path);
/*! \brief Destructor
*
* Close the output file (using the system call `close()`)
*
* \todo Implement destructor
*/
virtual ~FileOut();
/*! \brief Get path of the output file
*
* \return Path to output file (as defined in constructor)
*
* \todo Implement Method
*/
const char * getPath();
/*! \brief Number of output files which are currently opened (with this class)
*
* \return Number of active files
*
* \todo Implement Method
*/
static int count();
/*! \brief Write the string to the open file.
*
* The implementation should only use the system calls `write()` and `fsync()`.
*
* \todo Implement virtual Method
*/
virtual void flush() override; //NOLINT
};

36
test-stream/test.cc Normal file
View File

@ -0,0 +1,36 @@
#include "console_out.h"
#include "file_out.h"
ConsoleOut cout;
FileOut foo("foo.txt");
int main() {
cout << "Console Test <stream result> -> <expected>" << endl;
cout << " bool: " << true << " -> true" << endl;
cout << " zero: " << 0 << " -> 0" << endl;
cout << " binary: " << bin << 42 << dec << " -> 0b101010" << endl;
cout << " octal: " << oct << 42 << dec << " -> 052" << endl;
cout << " hex: " << hex << 42 << dec << " -> 0x2a" << endl;
cout << " uint64_t max: " << ~((unsigned long long)0) << " -> 18446744073709551615" << endl;
cout << " int64_t max: " << ~(1ll<<63) << " -> 9223372036854775807" << endl;
cout << " int64_t min: " << (1ll<<63) << " -> -9223372036854775808" << endl;
cout << " some int64_t: " << (-1234567890123456789) << " -> -1234567890123456789" << endl;
cout << " some int64_t: " << (1234567890123456789) << " -> 1234567890123456789" << endl;
cout << " pointer: " << reinterpret_cast<void*>(1994473406541717165ull) << " -> 0x1badcafefee1dead" << endl;
cout << endl;
cout << "File Test" << endl
<< " currently open: " << FileOut::count() << endl
<< " writing into '" << foo.getPath() << "'..." << endl;
foo << "C makes it easy to shoot yourself in the foot;" << endl;
foo << "C++ makes it harder, but when you do it blows your whole leg off." << endl;
{
FileOut bar("bar.txt");
cout << " opened the " << FileOut::count() << ". file, " << endl;
cout << " writing into '" << bar.getPath() << "'..." << endl;
bar << "Anyone who claims to have the perfect programming language is either a fool or a salesman or both" << endl;
}
cout << " having only " << FileOut::count() << " file opened since the other is out of scope" << endl;
return 0;
}