Skip to content

Commit

Permalink
June 2021.
Browse files Browse the repository at this point in the history
  • Loading branch information
KockaAdmiralac committed Jun 21, 2021
1 parent c61fd1c commit f20981d
Show file tree
Hide file tree
Showing 2 changed files with 236 additions and 0 deletions.
139 changes: 139 additions & 0 deletions md/2021/6/k-sol.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
2021/jun/Kolokvijum - Jun 2021 - Resenja.pdf
--------------------------------------------------------------------------------
segment
- VA(32): Segment(12). Offset(20)
- PA(40)

```cpp
const unsigned SEG_WIDTH = 12, OFFS_WIDTH = 20,
MAX_SEG_SIZE = 1U<<OFFS_WIDTH;
inline void setSMTEntry(unsigned long* smt,
unsigned seg,
unsigned limit,
unsigned long paddr,
unsigned short rwx) {
smt[seg] = (paddr<<(OFFS_WIDTH+3)) | (limit<<3) | rwx;
}

void initSegment(SegDesc* sd, unsigned long* smt) {
unsigned size = sd->size;
unsigned saddr = sd->startAddr;
while (size > 0) {
setSMTEntry(smt, saddr>>OFFS_WIDTH,
(size>MAX_SEG_SIZE?MAX_SEG_SIZE-1:size-1), 0, sd->rwx);
if (size < MAX_SEG_SIZE) break;
size -= MAX_SEG_SIZE;
saddr += MAX_SEG_SIZE;
}
}
```
--------------------------------------------------------------------------------
semimpl
```cpp
void Semaphore::wait() {
lock(lck);
Thread* oldRunning = Thread::runningThread;
if (--val < 0)
this->blocked.put(oldRunning);
else
Scheduler::put(oldRunning);
Thread* newRunning = Thread::runningThread = Scheduler::get();
if (oldRunning != newRunning)
Thread::yield(oldRunning, newRunning);
unlock(lck);
}
void Semaphore::signal() {
lock(lck);
if (++val <= 0)
Scheduler::put(this->blocked.get());
Thread* oldRunning = Thread::runningThread;
Scheduler::put(oldRunning);
Thread* newRunning = Thread::runningThread = Scheduler::get();
if (oldRunning != newRunning)
Thread::yield(oldRunning, newRunning);
unlock(lck);
}
```

--------------------------------------------------------------------------------
ioblock
```cpp
Byte* BlockIOCache::getBlock(BlkNo blk) {
// Find the requested block in the cache and return it if present:
int entry = hash(blk);
for (int i = map[entry]; i != -1; i = entries[i].next) {
if (entries[i].blkNo==blk) {
entries[i].refCounter++;
return entries[i].buf;
}
}
// The block is not in the cache, find a free slot to load it:
if (freeHead == -1) evict();
if (freeHead == -1) return 0; // Error: cannot find space
int free = freeHead;
freeHead = entries[freeHead].next;
// Load the requested block:
entries[free].blkNo = blk;
entries[free].refCounter = 1;
entries[free].next = map[entry];
map[entry] = free;
ioRead(dev, blk, entries[free].buf);
return entries[free].buf;
}
```
--------------------------------------------------------------------------------
fsintr
```cpp
#include <sys/stat.h>
#include <fcntl.h>
class IFStream {
public:
IFStream(const char* path);
~IFStream() {
if (fd >= 0) close(fd);
}
bool eof() const { return isEOF; }
bool err() const { return isErr; }
char getc();
protected:
inline void fetch();
private:
static const size_t BLOCK_SIZE = ..., CHAR_SIZE = 2;
int fd;
bool isEOF, isErr;
char buffer[(BLOCK_SIZE + CHAR_SIZE – 1)/CHAR_SIZE];
ssize_t curPos, size;
};
IFStream::IFStream(const char* path) : isEOF(false), isErr(false),
curPos(-1), size(-1) {
fd = open(path, O_RDONLY);
if (fd == -1) {
isErr = isEOF = true;
return;
}
fetch();
}
inline void IFStream::fetch() {
size = read(fd, buffer, BLOCK_SIZE);
if (size == -1) isErr = true;
if (size <= 0) isEOF = true;
curPos = 0;
}
char IFStream::getc() {
if (!isErr && !isEOF && curPos < size) {
char c = buffer[curPos++];
if (curPos >= size)
if (size < BLOCK_SIZE) isEOF = true;
else fetch();
return c;
}
return '\-1';
}
```
97 changes: 97 additions & 0 deletions md/2021/6/k.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
2021/jun/Kolokvijum - Jun 2021.pdf
--------------------------------------------------------------------------------
segment
Neki sistem ima segmentnu organizaciju memorije. Virtuelna adresa je 32-bitna, adresibilna jedinica je bajt, a maksimalna veličina fizičkog segmenta je 1 MB. Fizički adresni prostor je veličine 1 TB. Jedan ulaz u SMT-u sadrži prava pristupa *rwx* u najniža tri bita, granicu fizičkog segmenta (*limit* u opsegu od 0 do maksimalne veličine segmenta minus 1) u bitima do njih, a zatim fizičku adresu u bitima do njih; ovaj deskriptor (ulaz u SMT-u) zauzima najmanji potreban ceo broj bajtova.

Operativni sistem alocira segmente na zahtev, tako da pri kreiranju procesa ne alocira i ne učitava nijedan fizički segment. Vrednost 0 u polju za fizičku adresu u deskriptoru segmenta u SMT-u označava da preslikavanje nije moguće (segment nije alociran ili nije učitan).

Jedan alociran logički segment procesa opisan je deskriptorom tipa `SegDesc` u kom su, između ostalog, sledeća polja:

- `unsigned startAddr`: početna virtuelna adresa logičkog segmenta, svakako poravnata na početak fizičkog segmenta;
- `unsigned size`: veličina logičkog segmenta u bajtovima (može biti i veća od maksimalne veličine fizičkog segmenta);
- `unsigned short rwx`: prava pristupa za ceo logički segment u tri najniža bita.

Implementirati sledeću funkciju:
```cpp
void initSegment (SegDesc* sd, unsigned long* smt);
```
Ovu funkciju poziva kod kernela kada inicijalizuje SMT novokreiranog procesa za svaki logički segment sa datim deskriptorom `sd`. Na već alociran SMT ukazuje `smt`. Veličine tipova su sledeće: `int` – 32 bita, `long` – 64 bita, `short` – 16 bita.
--------------------------------------------------------------------------------
semimpl
U Školskom jezgru implementirana je statička operacija klase `Thread`
```cpp
void Thread::yield (Thread* oldRunning, Thread* newRunning);
```
koja obavlja promenu konteksta oduzimajući procesor (tekućoj) niti na koju pokazuje parametar `oldRunning` i predajući procesor niti na koju pokazuje parametar `newRunning`. Korišćenjem ove operacije implementirati operacije `wait` i `signal` klase `Semaphore`, s tim da se uvek, pa i kod neblokirajućih poziva obavlja promena konteksta ukoliko raspoređivač odabere neku drugu nit za izvršavanje. U redu spremnih uvek se nalazi barem neka nit, makar nit *idle* koja ne radi ništa korisno (samo troši procesorsko vreme instrukcijama bez efekta).

--------------------------------------------------------------------------------
ioblock
U nekom sistemu implementira se keš blokova sa blokovskih uređaja („diskova“) kodom koji je dat u nastavku. Za svaki uređaj sa datim identifikatorom pravi se jedan objekat klase `BlockIOCache`, inicijalizovan tim identifikatorom, koji predstavlja keš blokova sa tog uređaja. Keš je kapaciteta `CACHESIZE` blokova veličine `BLKSIZE`. Keš je interno organizovan kao heš mapa `map` sa `MAPSIZE` ulaza. Svaki ulaz niza `map` sadrži glavu liste keširanih blokova koji se preslikavaju u taj ulaz. Funkcija `hash` je heš funkcija koja preslikava broj bloka u ulaz u nizu `map`. Glava liste, kao i pokazivač na sledeći element u listi čuvaju se kao indeksi elementa niza `entries` koji sadrži keširane blokove; vrednost -1 označava kraj (*null*). Svaki element niza `entries` je struktura tipa `CacheEntry` u kojoj je polje `blkNo` broj bloka koji je keširan u tom elementu, polje `next` ukazuje na sledeći element liste, a polje `buf` je sadržaj samog bloka.

Na početku složene operacije sa uređajem, kod koji koristi keš najpre traži da je potrebni blok učitan pozivom funkcije `getBlock` koja vraća pokazivač na niz bajtova u baferu – učitanom bloku. Pošto više ovakvih složenih operacija može biti ugnježdeno, blok iz keša može biti izbačen (zamenjen drugim) samo ako ga više niko ne koristi, što se realizuje brojanjem referenci u polju `refCounter` strukture `CacheEntry`.

Član `freeHead` je glava liste slobodnih elemenata u nizu `entries` (-1 ako slobodnih nema). Funkcija `evict` izbacuje jedan keširani blok iz punog keša, ukoliko takav može da nađe, oslobađa njegov ulaz i stavlja ga u listu slobodnih.

Implementirati funkciju `getBlock` koja treba da obezbedi da je traženi blok u kešu, odnosno učita ga ako nije. Ako nema mesta u kešu jer nijedan blok ne može da se izbaci, treba vratiti *null*. Ostale članice date klase su implementirane, a na raspolaganju je i funkcija koja učitava blok na dati uređaj:
```cpp
void ioRead(int device, BlkNo blk, Byte* buffer);

typedef unsigned char Byte; // Unit of memory
typedef long long BlkNo; // Device block number
const unsigned BLKSIZE = ...; // Block size in Bytes
class BlockIOCache {
public:
BlockIOCache(int device);
Byte* getBlock(BlkNo blk);
...
protected:
static int hash(BlkNo);
void evict();
private:
static const unsigned CACHESIZE = ...; // Cache size in blocks
static const unsigned MAPSIZE = ...; // Hash map size in entries
struct CacheEntry {
BlkNo blkNo;
int next;
int refCounter;
Byte buf[BLKSIZE];
};
int dev;
int map[MAPSIZE]; // Hash map
CacheEntry entries[CACHESIZE]; // Cache
int freeHead; // Free entries list head
};
```
--------------------------------------------------------------------------------
fsintr
Na raspolaganju je POSIX API za fajlove:
```cpp
int open(const char* path, int flags);
int close(int fd);
ssize_t read(int fd, void *buf, size_t count);
```
Tip `ssize_t` je označen celobrojni tip, isti kao `size_t`, samo što može da prihvati i vrednost -1. Funkcija `read` vraća stvarno učitan broj bajtova (0 ili više); ako je taj broj manji od `count`, stiglo se do kraja fajla. Funkcije `open`, `close` i `read` vraćaju -1 u slučaju greške.

Korišćenjem ovog interfejsa realizovati apstrakciju `IFStream` kao klasu čiji je interfejs dat dole. Ova klasa apstrahuje ulazni znakovni tok vezan za fajl. Staza do fajla zadaje se parametrom konstruktora. Zatvaranje fajla treba obezbediti destruktorom. Operacija `getc` vraća jedan znak učitan sa toka. Kada se došlo do kraja fajla, operacija `eof` vraća `true`. Ukoliko je u nekoj ranijoj operaciji sa tokom, uključujući i otvaranje, došlo do greške, funkcije `err` i `eof` vraćaju `true`. Ukoliko je tok u stanju greške ili se stiglo do njegovog kraja, operacija `getc` treba da vraća `'\-1'`. Učitavanje treba da bude što je moguće efikasnije u smislu da se sa uređaja učitava najmanji mogući broj blokova za sekvencijalni pristup. Veličina bloka u bajtovima je `BLOCK_SIZE`, a veličina znakova u bajtovima je `CHAR_SIZE`.
```cpp
class IFStream {
public:
IFStream(const char* path);
~IFStream();
bool eof() const;
bool err() const;
char getc();
private:
static const size_t BLOCK_SIZE = ..., CHAR_SIZE = 2;
};
```
Ova apstrakcija može se koristiti ovako:
```cpp
IFStream str("myfile.txt");
while (!str.err() && !str.eof()) {
char c = str.getc();
...
}
```

0 comments on commit f20981d

Please sign in to comment.