mirror of
https://github.com/caperren/school_archives.git
synced 2025-11-09 13:41:13 +00:00
Added OS II assignments
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* File: main.c
|
||||
* Author: caperren
|
||||
*
|
||||
* Created on April 13, 2018, 7:27 PM
|
||||
*/
|
||||
|
||||
/*
|
||||
* Important implementation notes...
|
||||
* Consumer prints out number in struct on consumption
|
||||
* Timeout is how long before consumer is done with item (2-7 seconds)
|
||||
* Producer waits 3-7 seconds
|
||||
* Max buffer size is 32
|
||||
* Consumer/s and producer need lock on buffer when doing things
|
||||
* If nothing in queue, consumer blocks until there is
|
||||
*/
|
||||
|
||||
#include "mt19937ar.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
// Program defines you might want to change
|
||||
#define MAX_BUFFER_SIZE 32
|
||||
|
||||
#define MIN_RANDOM_PRODUCER 3
|
||||
#define MAX_RANDOM_PRODUCER 7
|
||||
|
||||
#define MIN_RANDOM_CONSUMER 2
|
||||
#define MAX_RANDOM_CONSUMER 9
|
||||
|
||||
//RDRAND value to check for
|
||||
#define RDRAND_FLAG (1 << 30)
|
||||
|
||||
// Data structure for the buffer elements
|
||||
struct two_values {
|
||||
uint8_t number;
|
||||
uint8_t work_timeout;
|
||||
};
|
||||
|
||||
//Storage containers and mutex for access
|
||||
struct two_values storage_buffer[MAX_BUFFER_SIZE];
|
||||
uint16_t tasks_in_buffer = 0;
|
||||
|
||||
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
// Get random number based on whether rdrand is supported.
|
||||
uint8_t get_random_number(uint8_t min, uint8_t max) {
|
||||
uint8_t rand_val;
|
||||
unsigned long seed;
|
||||
|
||||
unsigned int eax;
|
||||
unsigned int ebx;
|
||||
unsigned int ecx;
|
||||
unsigned int edx;
|
||||
|
||||
eax = 0x01;
|
||||
|
||||
// ASM for checking if RDRAND supported
|
||||
__asm__ __volatile__("cpuid"
|
||||
: "=a" (eax),
|
||||
"=b" (ebx),
|
||||
"=c" (ecx),
|
||||
"=d" (edx)
|
||||
: "a" (1),
|
||||
"c" (0)
|
||||
);
|
||||
|
||||
// Seed random with /dev/random
|
||||
int random = open("/dev/random", O_RDONLY);
|
||||
read(random, &seed, sizeof (seed));
|
||||
|
||||
unsigned int random_value;
|
||||
|
||||
if ((ecx & RDRAND_FLAG) == RDRAND_FLAG) {
|
||||
char return_code = 0;
|
||||
char count = 0;
|
||||
|
||||
// ASM for RDRAND
|
||||
while(return_code != 1 && count < 10){
|
||||
__asm__ volatile(
|
||||
"rdrand %0 ; setc %1"
|
||||
: "=r" (random_value), "=qm" (return_code)
|
||||
);
|
||||
|
||||
count++;
|
||||
}
|
||||
} else {
|
||||
// Twister if RDRAND not supported
|
||||
init_genrand(seed);
|
||||
random_value = genrand_int32();
|
||||
}
|
||||
|
||||
return (random_value % (max + 1 - min)) + min;
|
||||
}
|
||||
|
||||
void *consume_buffer_items(){
|
||||
uint8_t number;
|
||||
uint8_t work_timeout;
|
||||
|
||||
while(1){
|
||||
// This waits for a task to exist, then makes a temporary copy
|
||||
// of the data in the last item in the queue.
|
||||
// It then removes the item, while mutex locking during all of this
|
||||
while(tasks_in_buffer == 0);
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
number = storage_buffer[tasks_in_buffer - 1].number;
|
||||
work_timeout = storage_buffer[tasks_in_buffer - 1].work_timeout;
|
||||
storage_buffer[tasks_in_buffer - 1].number = 0;
|
||||
storage_buffer[tasks_in_buffer - 1].work_timeout = 0;
|
||||
tasks_in_buffer--;
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
printf("Consumer found number: %u. Now waiting %u seconds.\n", number, work_timeout);
|
||||
fflush(stdout);
|
||||
|
||||
sleep(work_timeout);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
pthread_t consumer_thread;
|
||||
|
||||
// This makes the consumer thread
|
||||
if(pthread_create(&consumer_thread, NULL, consume_buffer_items, NULL)) {
|
||||
fprintf(stderr, "Error creating thread\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
//Zero out array
|
||||
for(uint16_t i = 0 ; i < MAX_BUFFER_SIZE ; i++){
|
||||
storage_buffer[i].number = 0;
|
||||
storage_buffer[i].work_timeout = 0;
|
||||
}
|
||||
|
||||
uint8_t number;
|
||||
uint8_t work_timeout;
|
||||
uint8_t producer_sleep;
|
||||
|
||||
while(1){
|
||||
// This generates values for a new buffer element, waits until theres
|
||||
// space in the buffer, then adds and item to the buffer
|
||||
number = get_random_number(0, UINT8_MAX);
|
||||
work_timeout = get_random_number(MIN_RANDOM_CONSUMER, MAX_RANDOM_CONSUMER);
|
||||
producer_sleep = get_random_number(MIN_RANDOM_PRODUCER, MAX_RANDOM_PRODUCER);
|
||||
|
||||
while(tasks_in_buffer == MAX_BUFFER_SIZE);
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
storage_buffer[tasks_in_buffer].number = number;
|
||||
storage_buffer[tasks_in_buffer].work_timeout = work_timeout;
|
||||
tasks_in_buffer++;
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
printf("Producer adding number: %u. Consumers's delay will be %u seconds. Producer waiting %u seconds.\n", number, work_timeout, producer_sleep);
|
||||
fflush(stdout);
|
||||
|
||||
sleep(producer_sleep);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
all: clean build
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
rm -f concurrency1
|
||||
|
||||
build:
|
||||
gcc main.c mt19937ar.h -o concurrency1 -std=c99 -pthread
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
A C-program for MT19937, with initialization improved 2002/1/26.
|
||||
Coded by Takuji Nishimura and Makoto Matsumoto.
|
||||
|
||||
Before using, initialize the state by using init_genrand(seed)
|
||||
or init_by_array(init_key, key_length).
|
||||
|
||||
Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of its contributors may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
Any feedback is very welcome.
|
||||
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
|
||||
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Period parameters */
|
||||
#define N 624
|
||||
#define M 397
|
||||
#define MATRIX_A 0x9908b0dfUL /* constant vector a */
|
||||
#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
|
||||
#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
|
||||
|
||||
static unsigned long mt[N]; /* the array for the state vector */
|
||||
static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */
|
||||
|
||||
/* initializes mt[N] with a seed */
|
||||
void init_genrand(unsigned long s)
|
||||
{
|
||||
mt[0]= s & 0xffffffffUL;
|
||||
for (mti=1; mti<N; mti++) {
|
||||
mt[mti] =
|
||||
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
|
||||
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
|
||||
/* In the previous versions, MSBs of the seed affect */
|
||||
/* only MSBs of the array mt[]. */
|
||||
/* 2002/01/09 modified by Makoto Matsumoto */
|
||||
mt[mti] &= 0xffffffffUL;
|
||||
/* for >32 bit machines */
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize by an array with array-length */
|
||||
/* init_key is the array for initializing keys */
|
||||
/* key_length is its length */
|
||||
/* slight change for C++, 2004/2/26 */
|
||||
void init_by_array(unsigned long init_key[], int key_length)
|
||||
{
|
||||
int i, j, k;
|
||||
init_genrand(19650218UL);
|
||||
i=1; j=0;
|
||||
k = (N>key_length ? N : key_length);
|
||||
for (; k; k--) {
|
||||
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
|
||||
+ init_key[j] + j; /* non linear */
|
||||
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
|
||||
i++; j++;
|
||||
if (i>=N) { mt[0] = mt[N-1]; i=1; }
|
||||
if (j>=key_length) j=0;
|
||||
}
|
||||
for (k=N-1; k; k--) {
|
||||
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
|
||||
- i; /* non linear */
|
||||
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
|
||||
i++;
|
||||
if (i>=N) { mt[0] = mt[N-1]; i=1; }
|
||||
}
|
||||
|
||||
mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
|
||||
}
|
||||
|
||||
/* generates a random number on [0,0xffffffff]-interval */
|
||||
unsigned long genrand_int32(void)
|
||||
{
|
||||
unsigned long y;
|
||||
static unsigned long mag01[2]={0x0UL, MATRIX_A};
|
||||
/* mag01[x] = x * MATRIX_A for x=0,1 */
|
||||
|
||||
if (mti >= N) { /* generate N words at one time */
|
||||
int kk;
|
||||
|
||||
if (mti == N+1) /* if init_genrand() has not been called, */
|
||||
init_genrand(5489UL); /* a default initial seed is used */
|
||||
|
||||
for (kk=0;kk<N-M;kk++) {
|
||||
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
||||
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
}
|
||||
for (;kk<N-1;kk++) {
|
||||
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
||||
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
}
|
||||
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
|
||||
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
|
||||
mti = 0;
|
||||
}
|
||||
|
||||
y = mt[mti++];
|
||||
|
||||
/* Tempering */
|
||||
y ^= (y >> 11);
|
||||
y ^= (y << 7) & 0x9d2c5680UL;
|
||||
y ^= (y << 15) & 0xefc60000UL;
|
||||
y ^= (y >> 18);
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
/* generates a random number on [0,0x7fffffff]-interval */
|
||||
long genrand_int31(void)
|
||||
{
|
||||
return (long)(genrand_int32()>>1);
|
||||
}
|
||||
|
||||
/* generates a random number on [0,1]-real-interval */
|
||||
double genrand_real1(void)
|
||||
{
|
||||
return genrand_int32()*(1.0/4294967295.0);
|
||||
/* divided by 2^32-1 */
|
||||
}
|
||||
|
||||
/* generates a random number on [0,1)-real-interval */
|
||||
double genrand_real2(void)
|
||||
{
|
||||
return genrand_int32()*(1.0/4294967296.0);
|
||||
/* divided by 2^32 */
|
||||
}
|
||||
|
||||
/* generates a random number on (0,1)-real-interval */
|
||||
double genrand_real3(void)
|
||||
{
|
||||
return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0);
|
||||
/* divided by 2^32 */
|
||||
}
|
||||
|
||||
/* generates a random number on [0,1) with 53-bit resolution*/
|
||||
double genrand_res53(void)
|
||||
{
|
||||
unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6;
|
||||
return(a*67108864.0+b)*(1.0/9007199254740992.0);
|
||||
}
|
||||
/* These real versions are due to Isaku Wada, 2002/01/09 added */
|
||||
|
||||
//int main(void)
|
||||
//{
|
||||
// int i;
|
||||
// unsigned long init[4]={0x123, 0x234, 0x345, 0x456}, length=4;
|
||||
// init_by_array(init, length);
|
||||
// printf("1000 outputs of genrand_int32()\n");
|
||||
// for (i=0; i<1000; i++) {
|
||||
// printf("%10lu ", genrand_int32());
|
||||
// if (i%5==4) printf("\n");
|
||||
// }
|
||||
// printf("\n1000 outputs of genrand_real2()\n");
|
||||
// for (i=0; i<1000; i++) {
|
||||
// printf("%10.8f ", genrand_real2());
|
||||
// if (i%5==4) printf("\n");
|
||||
// }
|
||||
// return 0;
|
||||
//}
|
||||
@@ -0,0 +1,5 @@
|
||||
Corwin Perren - Concurrency HW 1
|
||||
|
||||
To make this program on the os server, cd into this directory and run "make".
|
||||
|
||||
To run the program, type "./concurrency1" into the terminal and hit enter.
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* File: main.c
|
||||
* Author: caperren
|
||||
*
|
||||
* Created on April 27th, 2018
|
||||
*/
|
||||
|
||||
#include "mt19937ar.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/param.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
// Program defines you might want to change
|
||||
#define NUM_PHILOSOPHERS 5
|
||||
|
||||
#define MIN_RANDOM_EAT 2
|
||||
#define MAX_RANDOM_EAT 9
|
||||
|
||||
#define MIN_RANDOM_THINK 1
|
||||
#define MAX_RANDOM_THINK 20
|
||||
|
||||
uint8_t* philosopher_names[] = {
|
||||
"Plato",
|
||||
"Aristotle",
|
||||
"Socrates",
|
||||
"Confucius",
|
||||
"Voltaire"
|
||||
};
|
||||
|
||||
//RDRAND value to check for
|
||||
#define RDRAND_FLAG (1 << 30)
|
||||
|
||||
sem_t fork_semaphores[NUM_PHILOSOPHERS];
|
||||
uint32_t philosopher_eat_counts[NUM_PHILOSOPHERS];
|
||||
|
||||
// Get random number based on whether rdrand is supported.
|
||||
uint8_t get_random_number(uint8_t min, uint8_t max) {
|
||||
uint8_t rand_val;
|
||||
unsigned long seed;
|
||||
|
||||
unsigned int eax;
|
||||
unsigned int ebx;
|
||||
unsigned int ecx;
|
||||
unsigned int edx;
|
||||
|
||||
eax = 0x01;
|
||||
|
||||
// ASM for checking if RDRAND supported
|
||||
__asm__ __volatile__("cpuid"
|
||||
: "=a" (eax),
|
||||
"=b" (ebx),
|
||||
"=c" (ecx),
|
||||
"=d" (edx)
|
||||
: "a" (1),
|
||||
"c" (0)
|
||||
);
|
||||
|
||||
// Seed random with /dev/random
|
||||
int random = open("/dev/random", O_RDONLY);
|
||||
read(random, &seed, sizeof (seed));
|
||||
|
||||
unsigned int random_value;
|
||||
|
||||
if ((ecx & RDRAND_FLAG) == RDRAND_FLAG) {
|
||||
char return_code = 0;
|
||||
char count = 0;
|
||||
|
||||
// ASM for RDRAND
|
||||
while(return_code != 1 && count < 10){
|
||||
__asm__ volatile(
|
||||
"rdrand %0 ; setc %1"
|
||||
: "=r" (random_value), "=qm" (return_code)
|
||||
);
|
||||
|
||||
count++;
|
||||
}
|
||||
} else {
|
||||
// Twister if RDRAND not supported
|
||||
init_genrand(seed);
|
||||
random_value = genrand_int32();
|
||||
}
|
||||
|
||||
return (random_value % (max + 1 - min)) + min;
|
||||
}
|
||||
|
||||
void think(uint8_t *name){
|
||||
uint8_t random = get_random_number(MIN_RANDOM_THINK, MAX_RANDOM_THINK);
|
||||
|
||||
printf("%s thinking for %u seconds.\n", name, random);
|
||||
fflush(stdout);
|
||||
|
||||
sleep(random);
|
||||
}
|
||||
|
||||
void eat(uint8_t *name){
|
||||
uint8_t random = get_random_number(MIN_RANDOM_EAT, MAX_RANDOM_EAT);
|
||||
|
||||
printf("%s eating for %u seconds.\n", name, random);
|
||||
fflush(stdout);
|
||||
|
||||
sleep(random);
|
||||
}
|
||||
|
||||
void *philosopher(void *number){
|
||||
// Store values that will be useful as the thread runs
|
||||
uint16_t philosophers_number = *((uint16_t *) number);
|
||||
uint16_t philosophers_number_plus_one = philosophers_number + 1;
|
||||
uint16_t fork_num_plus_one = philosophers_number_plus_one % NUM_PHILOSOPHERS;
|
||||
|
||||
while(1){
|
||||
// Think
|
||||
think(philosopher_names[philosophers_number]);
|
||||
|
||||
// Get forks
|
||||
printf("%s waiting for forks %u and %u.\n", philosopher_names[philosophers_number], philosophers_number, fork_num_plus_one);
|
||||
fflush(stdout);
|
||||
|
||||
sem_wait(&fork_semaphores[MIN(philosophers_number, fork_num_plus_one)]);
|
||||
sem_wait(&fork_semaphores[MAX(philosophers_number, fork_num_plus_one)]);
|
||||
|
||||
printf("%s now has forks %u and %u.\n", philosopher_names[philosophers_number], philosophers_number, fork_num_plus_one);
|
||||
fflush(stdout);
|
||||
|
||||
// Eat
|
||||
eat(philosopher_names[philosophers_number]);
|
||||
philosopher_eat_counts[philosophers_number]++;
|
||||
|
||||
// Release forks
|
||||
printf("%s releasing forks %u and %u.\n", philosopher_names[philosophers_number], philosophers_number, fork_num_plus_one);
|
||||
fflush(stdout);
|
||||
|
||||
sem_post(&fork_semaphores[philosophers_number]);
|
||||
sem_post(&fork_semaphores[fork_num_plus_one]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Containers to hold our threads, and the philosopher index
|
||||
pthread_t consumer_threads[NUM_PHILOSOPHERS];
|
||||
uint16_t philosophers_numbers[NUM_PHILOSOPHERS];
|
||||
|
||||
// Initialize semaphores, and arrays used to keep track of things
|
||||
for(uint16_t i = 0 ; i < NUM_PHILOSOPHERS ; i++){
|
||||
sem_init(&fork_semaphores[i], 0, 1);
|
||||
philosophers_numbers[i] = i;
|
||||
philosopher_eat_counts[i] = 0;
|
||||
}
|
||||
|
||||
// Create all the philosopher threads
|
||||
for(uint16_t i = 0 ; i < NUM_PHILOSOPHERS ; i++){
|
||||
if(pthread_create(&consumer_threads[i], NULL, philosopher, &philosophers_numbers[i])) {
|
||||
fprintf(stderr, "Error creating thread\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// This monitoring while loop prints our the eating counts of the
|
||||
// philosophers so you can easily see how often they've ate without
|
||||
// having to dig through the text output. It runs once every five seconds.
|
||||
while(1){
|
||||
sleep(5);
|
||||
|
||||
printf("\n####################\nEat Counts\n");
|
||||
|
||||
for(uint16_t i = 0 ; i < NUM_PHILOSOPHERS ; i++){
|
||||
printf("%s: %u\n", philosopher_names[i], philosopher_eat_counts[i]);
|
||||
}
|
||||
|
||||
printf("####################\n\n");
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
all: clean build
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
rm -f concurrency2
|
||||
|
||||
build:
|
||||
gcc main.c mt19937ar.h -o concurrency2 -std=c99 -lpthread -lrt
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
A C-program for MT19937, with initialization improved 2002/1/26.
|
||||
Coded by Takuji Nishimura and Makoto Matsumoto.
|
||||
|
||||
Before using, initialize the state by using init_genrand(seed)
|
||||
or init_by_array(init_key, key_length).
|
||||
|
||||
Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of its contributors may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
Any feedback is very welcome.
|
||||
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
|
||||
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Period parameters */
|
||||
#define N 624
|
||||
#define M 397
|
||||
#define MATRIX_A 0x9908b0dfUL /* constant vector a */
|
||||
#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
|
||||
#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
|
||||
|
||||
static unsigned long mt[N]; /* the array for the state vector */
|
||||
static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */
|
||||
|
||||
/* initializes mt[N] with a seed */
|
||||
void init_genrand(unsigned long s)
|
||||
{
|
||||
mt[0]= s & 0xffffffffUL;
|
||||
for (mti=1; mti<N; mti++) {
|
||||
mt[mti] =
|
||||
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
|
||||
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
|
||||
/* In the previous versions, MSBs of the seed affect */
|
||||
/* only MSBs of the array mt[]. */
|
||||
/* 2002/01/09 modified by Makoto Matsumoto */
|
||||
mt[mti] &= 0xffffffffUL;
|
||||
/* for >32 bit machines */
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize by an array with array-length */
|
||||
/* init_key is the array for initializing keys */
|
||||
/* key_length is its length */
|
||||
/* slight change for C++, 2004/2/26 */
|
||||
void init_by_array(unsigned long init_key[], int key_length)
|
||||
{
|
||||
int i, j, k;
|
||||
init_genrand(19650218UL);
|
||||
i=1; j=0;
|
||||
k = (N>key_length ? N : key_length);
|
||||
for (; k; k--) {
|
||||
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
|
||||
+ init_key[j] + j; /* non linear */
|
||||
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
|
||||
i++; j++;
|
||||
if (i>=N) { mt[0] = mt[N-1]; i=1; }
|
||||
if (j>=key_length) j=0;
|
||||
}
|
||||
for (k=N-1; k; k--) {
|
||||
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
|
||||
- i; /* non linear */
|
||||
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
|
||||
i++;
|
||||
if (i>=N) { mt[0] = mt[N-1]; i=1; }
|
||||
}
|
||||
|
||||
mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
|
||||
}
|
||||
|
||||
/* generates a random number on [0,0xffffffff]-interval */
|
||||
unsigned long genrand_int32(void)
|
||||
{
|
||||
unsigned long y;
|
||||
static unsigned long mag01[2]={0x0UL, MATRIX_A};
|
||||
/* mag01[x] = x * MATRIX_A for x=0,1 */
|
||||
|
||||
if (mti >= N) { /* generate N words at one time */
|
||||
int kk;
|
||||
|
||||
if (mti == N+1) /* if init_genrand() has not been called, */
|
||||
init_genrand(5489UL); /* a default initial seed is used */
|
||||
|
||||
for (kk=0;kk<N-M;kk++) {
|
||||
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
||||
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
}
|
||||
for (;kk<N-1;kk++) {
|
||||
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
||||
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
}
|
||||
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
|
||||
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
|
||||
mti = 0;
|
||||
}
|
||||
|
||||
y = mt[mti++];
|
||||
|
||||
/* Tempering */
|
||||
y ^= (y >> 11);
|
||||
y ^= (y << 7) & 0x9d2c5680UL;
|
||||
y ^= (y << 15) & 0xefc60000UL;
|
||||
y ^= (y >> 18);
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
/* generates a random number on [0,0x7fffffff]-interval */
|
||||
long genrand_int31(void)
|
||||
{
|
||||
return (long)(genrand_int32()>>1);
|
||||
}
|
||||
|
||||
/* generates a random number on [0,1]-real-interval */
|
||||
double genrand_real1(void)
|
||||
{
|
||||
return genrand_int32()*(1.0/4294967295.0);
|
||||
/* divided by 2^32-1 */
|
||||
}
|
||||
|
||||
/* generates a random number on [0,1)-real-interval */
|
||||
double genrand_real2(void)
|
||||
{
|
||||
return genrand_int32()*(1.0/4294967296.0);
|
||||
/* divided by 2^32 */
|
||||
}
|
||||
|
||||
/* generates a random number on (0,1)-real-interval */
|
||||
double genrand_real3(void)
|
||||
{
|
||||
return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0);
|
||||
/* divided by 2^32 */
|
||||
}
|
||||
|
||||
/* generates a random number on [0,1) with 53-bit resolution*/
|
||||
double genrand_res53(void)
|
||||
{
|
||||
unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6;
|
||||
return(a*67108864.0+b)*(1.0/9007199254740992.0);
|
||||
}
|
||||
/* These real versions are due to Isaku Wada, 2002/01/09 added */
|
||||
|
||||
//int main(void)
|
||||
//{
|
||||
// int i;
|
||||
// unsigned long init[4]={0x123, 0x234, 0x345, 0x456}, length=4;
|
||||
// init_by_array(init, length);
|
||||
// printf("1000 outputs of genrand_int32()\n");
|
||||
// for (i=0; i<1000; i++) {
|
||||
// printf("%10lu ", genrand_int32());
|
||||
// if (i%5==4) printf("\n");
|
||||
// }
|
||||
// printf("\n1000 outputs of genrand_real2()\n");
|
||||
// for (i=0; i<1000; i++) {
|
||||
// printf("%10.8f ", genrand_real2());
|
||||
// if (i%5==4) printf("\n");
|
||||
// }
|
||||
// return 0;
|
||||
//}
|
||||
@@ -0,0 +1,5 @@
|
||||
Corwin Perren - Concurrency HW 2
|
||||
|
||||
To make this program on the os server, cd into this directory and run "make".
|
||||
|
||||
To run the program, type "./concurrency2" into the terminal and hit enter.
|
||||
@@ -0,0 +1,9 @@
|
||||
all: clean build
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
rm -f concurrency3_problem1 concurrency3_problem2
|
||||
|
||||
build:
|
||||
gcc problem1.c mt19937ar.h -o concurrency3_problem1 -std=c99 -lpthread -lrt
|
||||
gcc problem2.c mt19937ar.h -o concurrency3_problem2 -std=c99 -lpthread -lrt
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
A C-program for MT19937, with initialization improved 2002/1/26.
|
||||
Coded by Takuji Nishimura and Makoto Matsumoto.
|
||||
|
||||
Before using, initialize the state by using init_genrand(seed)
|
||||
or init_by_array(init_key, key_length).
|
||||
|
||||
Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of its contributors may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
Any feedback is very welcome.
|
||||
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
|
||||
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Period parameters */
|
||||
#define N 624
|
||||
#define M 397
|
||||
#define MATRIX_A 0x9908b0dfUL /* constant vector a */
|
||||
#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
|
||||
#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
|
||||
|
||||
static unsigned long mt[N]; /* the array for the state vector */
|
||||
static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */
|
||||
|
||||
/* initializes mt[N] with a seed */
|
||||
void init_genrand(unsigned long s)
|
||||
{
|
||||
mt[0]= s & 0xffffffffUL;
|
||||
for (mti=1; mti<N; mti++) {
|
||||
mt[mti] =
|
||||
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
|
||||
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
|
||||
/* In the previous versions, MSBs of the seed affect */
|
||||
/* only MSBs of the array mt[]. */
|
||||
/* 2002/01/09 modified by Makoto Matsumoto */
|
||||
mt[mti] &= 0xffffffffUL;
|
||||
/* for >32 bit machines */
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize by an array with array-length */
|
||||
/* init_key is the array for initializing keys */
|
||||
/* key_length is its length */
|
||||
/* slight change for C++, 2004/2/26 */
|
||||
void init_by_array(unsigned long init_key[], int key_length)
|
||||
{
|
||||
int i, j, k;
|
||||
init_genrand(19650218UL);
|
||||
i=1; j=0;
|
||||
k = (N>key_length ? N : key_length);
|
||||
for (; k; k--) {
|
||||
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
|
||||
+ init_key[j] + j; /* non linear */
|
||||
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
|
||||
i++; j++;
|
||||
if (i>=N) { mt[0] = mt[N-1]; i=1; }
|
||||
if (j>=key_length) j=0;
|
||||
}
|
||||
for (k=N-1; k; k--) {
|
||||
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
|
||||
- i; /* non linear */
|
||||
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
|
||||
i++;
|
||||
if (i>=N) { mt[0] = mt[N-1]; i=1; }
|
||||
}
|
||||
|
||||
mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
|
||||
}
|
||||
|
||||
/* generates a random number on [0,0xffffffff]-interval */
|
||||
unsigned long genrand_int32(void)
|
||||
{
|
||||
unsigned long y;
|
||||
static unsigned long mag01[2]={0x0UL, MATRIX_A};
|
||||
/* mag01[x] = x * MATRIX_A for x=0,1 */
|
||||
|
||||
if (mti >= N) { /* generate N words at one time */
|
||||
int kk;
|
||||
|
||||
if (mti == N+1) /* if init_genrand() has not been called, */
|
||||
init_genrand(5489UL); /* a default initial seed is used */
|
||||
|
||||
for (kk=0;kk<N-M;kk++) {
|
||||
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
||||
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
}
|
||||
for (;kk<N-1;kk++) {
|
||||
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
||||
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
}
|
||||
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
|
||||
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
|
||||
mti = 0;
|
||||
}
|
||||
|
||||
y = mt[mti++];
|
||||
|
||||
/* Tempering */
|
||||
y ^= (y >> 11);
|
||||
y ^= (y << 7) & 0x9d2c5680UL;
|
||||
y ^= (y << 15) & 0xefc60000UL;
|
||||
y ^= (y >> 18);
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
/* generates a random number on [0,0x7fffffff]-interval */
|
||||
long genrand_int31(void)
|
||||
{
|
||||
return (long)(genrand_int32()>>1);
|
||||
}
|
||||
|
||||
/* generates a random number on [0,1]-real-interval */
|
||||
double genrand_real1(void)
|
||||
{
|
||||
return genrand_int32()*(1.0/4294967295.0);
|
||||
/* divided by 2^32-1 */
|
||||
}
|
||||
|
||||
/* generates a random number on [0,1)-real-interval */
|
||||
double genrand_real2(void)
|
||||
{
|
||||
return genrand_int32()*(1.0/4294967296.0);
|
||||
/* divided by 2^32 */
|
||||
}
|
||||
|
||||
/* generates a random number on (0,1)-real-interval */
|
||||
double genrand_real3(void)
|
||||
{
|
||||
return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0);
|
||||
/* divided by 2^32 */
|
||||
}
|
||||
|
||||
/* generates a random number on [0,1) with 53-bit resolution*/
|
||||
double genrand_res53(void)
|
||||
{
|
||||
unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6;
|
||||
return(a*67108864.0+b)*(1.0/9007199254740992.0);
|
||||
}
|
||||
/* These real versions are due to Isaku Wada, 2002/01/09 added */
|
||||
|
||||
//int main(void)
|
||||
//{
|
||||
// int i;
|
||||
// unsigned long init[4]={0x123, 0x234, 0x345, 0x456}, length=4;
|
||||
// init_by_array(init, length);
|
||||
// printf("1000 outputs of genrand_int32()\n");
|
||||
// for (i=0; i<1000; i++) {
|
||||
// printf("%10lu ", genrand_int32());
|
||||
// if (i%5==4) printf("\n");
|
||||
// }
|
||||
// printf("\n1000 outputs of genrand_real2()\n");
|
||||
// for (i=0; i<1000; i++) {
|
||||
// printf("%10.8f ", genrand_real2());
|
||||
// if (i%5==4) printf("\n");
|
||||
// }
|
||||
// return 0;
|
||||
//}
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* File: main.c
|
||||
* Author: caperren
|
||||
*
|
||||
* Created on April 27th, 2018
|
||||
*/
|
||||
|
||||
#include "mt19937ar.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/param.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
// Program defines you might want to change
|
||||
#define MAX_NUM_THREADS 4
|
||||
#define MAX_RESOURCE_USAGE 3
|
||||
|
||||
#define MIN_RANDOM_USE_WAIT 3
|
||||
#define MAX_RANDOM_USE_WAIT 5
|
||||
|
||||
//RDRAND value to check for
|
||||
#define RDRAND_FLAG (1 << 30)
|
||||
|
||||
sem_t resource_semaphore;
|
||||
uint8_t wait_for_resource_recovery = 0;
|
||||
|
||||
// Get random number based on whether rdrand is supported.
|
||||
uint8_t get_random_number(uint8_t min, uint8_t max) {
|
||||
uint8_t rand_val;
|
||||
unsigned long seed;
|
||||
|
||||
unsigned int eax;
|
||||
unsigned int ebx;
|
||||
unsigned int ecx;
|
||||
unsigned int edx;
|
||||
|
||||
eax = 0x01;
|
||||
|
||||
// ASM for checking if RDRAND supported
|
||||
__asm__ __volatile__("cpuid"
|
||||
: "=a" (eax),
|
||||
"=b" (ebx),
|
||||
"=c" (ecx),
|
||||
"=d" (edx)
|
||||
: "a" (1),
|
||||
"c" (0)
|
||||
);
|
||||
|
||||
// Seed random with /dev/random
|
||||
int random = open("/dev/random", O_RDONLY);
|
||||
read(random, &seed, sizeof (seed));
|
||||
|
||||
unsigned int random_value;
|
||||
|
||||
if ((ecx & RDRAND_FLAG) == RDRAND_FLAG) {
|
||||
char return_code = 0;
|
||||
char count = 0;
|
||||
|
||||
// ASM for RDRAND
|
||||
while(return_code != 1 && count < 10){
|
||||
__asm__ volatile(
|
||||
"rdrand %0 ; setc %1"
|
||||
: "=r" (random_value), "=qm" (return_code)
|
||||
);
|
||||
|
||||
count++;
|
||||
}
|
||||
} else {
|
||||
// Twister if RDRAND not supported
|
||||
init_genrand(seed);
|
||||
random_value = genrand_int32();
|
||||
}
|
||||
|
||||
return (random_value % (max + 1 - min)) + min;
|
||||
}
|
||||
|
||||
|
||||
void resource_user_wait(uint8_t id, uint8_t *wait_kind){
|
||||
uint8_t random = get_random_number(MIN_RANDOM_USE_WAIT, MAX_RANDOM_USE_WAIT);
|
||||
|
||||
printf("Resource user %d waiting %u seconds for %s.\n", id, random, wait_kind);
|
||||
fflush(stdout);
|
||||
|
||||
sleep(random);
|
||||
}
|
||||
|
||||
void *resource_user(void *thread_num){
|
||||
|
||||
uint8_t thread_number = *((uint8_t *)thread_num);
|
||||
|
||||
printf("Resourcing using thread with id: %d now running.\n", thread_number);
|
||||
fflush(stdout);
|
||||
|
||||
while(1){
|
||||
resource_user_wait(thread_number, "initial wait");
|
||||
|
||||
if(wait_for_resource_recovery){
|
||||
printf("Resource user %d waiting for recovery of all resources.\n", thread_number);
|
||||
fflush(stdout);
|
||||
while(wait_for_resource_recovery);
|
||||
}
|
||||
|
||||
sem_wait(&resource_semaphore);
|
||||
|
||||
printf("Resource user %d now using resource.\n", thread_number);
|
||||
fflush(stdout);
|
||||
|
||||
resource_user_wait(thread_number, "usage wait");
|
||||
|
||||
printf("Resource user %d done with resource.\n", thread_number);
|
||||
fflush(stdout);
|
||||
|
||||
sem_post(&resource_semaphore);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Containers to hold our threads, and the philosopher index
|
||||
pthread_t usage_threads[MAX_NUM_THREADS];
|
||||
uint8_t thread_id_numbers[MAX_NUM_THREADS];
|
||||
|
||||
// Initialize semaphores, and arrays used to keep track of things
|
||||
sem_init(&resource_semaphore, 0, MAX_RESOURCE_USAGE);
|
||||
|
||||
for(uint8_t i = 0 ; i < MAX_NUM_THREADS ; i++){
|
||||
thread_id_numbers[i] = i;
|
||||
}
|
||||
|
||||
// Create all the philosopher threads
|
||||
for(uint8_t i = 0 ; i < MAX_NUM_THREADS ; i++){
|
||||
if(pthread_create(&usage_threads[i], NULL, resource_user, &thread_id_numbers[i])) {
|
||||
fprintf(stderr, "Error creating thread\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int used_semaphores = 0;
|
||||
uint8_t resources_left = MAX_RESOURCE_USAGE;
|
||||
uint8_t last_resources_left_value = resources_left;
|
||||
|
||||
|
||||
while(1){
|
||||
sem_getvalue(&resource_semaphore, &used_semaphores);
|
||||
|
||||
resources_left = MAX_RESOURCE_USAGE - used_semaphores;
|
||||
|
||||
if(resources_left != last_resources_left_value){
|
||||
|
||||
printf("Manager ### Resources currently used: %d\n", resources_left);
|
||||
fflush(stdout);
|
||||
|
||||
if(resources_left == MAX_RESOURCE_USAGE){
|
||||
printf("Manager ### Maximum resources used. Locking out.\n");
|
||||
fflush(stdout);
|
||||
wait_for_resource_recovery = 1;
|
||||
}else if (resources_left == 0){
|
||||
wait_for_resource_recovery = 0;
|
||||
}
|
||||
|
||||
last_resources_left_value = resources_left;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
* File: main.c
|
||||
* Author: caperren
|
||||
*
|
||||
* Created on April 27th, 2018
|
||||
*/
|
||||
|
||||
#include "mt19937ar.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/param.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
////////// Program defines you might want to change //////////
|
||||
#define NUM_INSERTERS 2
|
||||
#define NUM_DELETERS 2
|
||||
#define NUM_SEARCHERS 2
|
||||
|
||||
#define MIN_NUMBER 0
|
||||
#define MAX_NUMBER 10
|
||||
|
||||
#define MIN_SLEEP_INSERTER 2
|
||||
#define MAX_SLEEP_INSERTER 4
|
||||
|
||||
#define MIN_SLEEP_SEARCHER 1
|
||||
#define MAX_SLEEP_SEARCHER 2
|
||||
|
||||
#define MIN_SLEEP_DELETER 10
|
||||
#define MAX_SLEEP_DELETER 15
|
||||
|
||||
////////// Global variables and structs for linked list //////////
|
||||
typedef struct linked_list {
|
||||
struct linked_list *next;
|
||||
uint16_t value;
|
||||
} linked_list;
|
||||
|
||||
linked_list *list_head = NULL;
|
||||
uint16_t list_size = 0;
|
||||
|
||||
|
||||
////////// Global variables and structs for threading and sempaphores //////////
|
||||
typedef struct light_switch {
|
||||
uint16_t counter;
|
||||
sem_t mutex;
|
||||
} light_switch;
|
||||
|
||||
|
||||
sem_t no_searches_semaphore;
|
||||
sem_t no_insertions_semaphore;
|
||||
sem_t insertion_mutex;
|
||||
|
||||
light_switch insertion_light_switch;
|
||||
light_switch search_light_switch;
|
||||
|
||||
|
||||
////////// Other global variables //////////
|
||||
//RDRAND value to check for
|
||||
#define RDRAND_FLAG (1 << 30)
|
||||
|
||||
// Get random number based on whether rdrand is supported.
|
||||
uint8_t get_random_number(uint8_t min, uint8_t max) {
|
||||
uint8_t rand_val;
|
||||
unsigned long seed;
|
||||
|
||||
unsigned int eax;
|
||||
unsigned int ebx;
|
||||
unsigned int ecx;
|
||||
unsigned int edx;
|
||||
|
||||
eax = 0x01;
|
||||
|
||||
// ASM for checking if RDRAND supported
|
||||
__asm__ __volatile__("cpuid"
|
||||
: "=a" (eax),
|
||||
"=b" (ebx),
|
||||
"=c" (ecx),
|
||||
"=d" (edx)
|
||||
: "a" (1),
|
||||
"c" (0)
|
||||
);
|
||||
|
||||
// Seed random with /dev/random
|
||||
int random = open("/dev/random", O_RDONLY);
|
||||
read(random, &seed, sizeof (seed));
|
||||
|
||||
unsigned int random_value;
|
||||
|
||||
if ((ecx & RDRAND_FLAG) == RDRAND_FLAG) {
|
||||
char return_code = 0;
|
||||
char count = 0;
|
||||
|
||||
// ASM for RDRAND
|
||||
while(return_code != 1 && count < 10){
|
||||
__asm__ volatile(
|
||||
"rdrand %0 ; setc %1"
|
||||
: "=r" (random_value), "=qm" (return_code)
|
||||
);
|
||||
|
||||
count++;
|
||||
}
|
||||
} else {
|
||||
// Twister if RDRAND not supported
|
||||
init_genrand(seed);
|
||||
random_value = genrand_int32();
|
||||
}
|
||||
|
||||
return (random_value % (max + 1 - min)) + min;
|
||||
}
|
||||
|
||||
void insert_linked_list(uint16_t value){
|
||||
linked_list *new = malloc(sizeof(linked_list));
|
||||
new->next = NULL;
|
||||
new->value = value;
|
||||
|
||||
if(list_head == NULL){
|
||||
list_head = new;
|
||||
}else{
|
||||
linked_list *cursor = list_head;
|
||||
|
||||
while(cursor->next != NULL){
|
||||
cursor = cursor->next;
|
||||
}
|
||||
cursor->next = new;
|
||||
}
|
||||
|
||||
list_size++;
|
||||
}
|
||||
|
||||
void delete_position_from_linked_list(uint16_t position) {
|
||||
linked_list *cursor_prev = list_head;
|
||||
linked_list *cursor_current = list_head;
|
||||
|
||||
if(list_head == NULL || position >= list_size){
|
||||
return;
|
||||
}
|
||||
|
||||
if(position == 0){
|
||||
list_head = cursor_current->next;
|
||||
free(cursor_current);
|
||||
}else{
|
||||
for(uint16_t i = 0 ; i < position ; i++){
|
||||
cursor_prev = cursor_current;
|
||||
cursor_current = cursor_current->next;
|
||||
}
|
||||
|
||||
cursor_prev->next = cursor_current->next;
|
||||
free(cursor_current);
|
||||
}
|
||||
|
||||
list_size--;
|
||||
}
|
||||
|
||||
int16_t position_of_value_linked_list(uint16_t value){
|
||||
linked_list *cursor_current = list_head;
|
||||
|
||||
if(list_head == NULL){
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint16_t count = 0;
|
||||
|
||||
do{
|
||||
if(cursor_current->value == value){
|
||||
return count;
|
||||
}
|
||||
|
||||
count++;
|
||||
cursor_current = cursor_current->next;
|
||||
}while(cursor_current != NULL);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void light_switch_lock(light_switch *current_light_switch, sem_t *current_semaphore){
|
||||
sem_wait(¤t_light_switch->mutex);
|
||||
current_light_switch->counter++;
|
||||
|
||||
if(current_light_switch->counter == 1){
|
||||
sem_wait(current_semaphore);
|
||||
}
|
||||
|
||||
sem_post(¤t_light_switch->mutex);
|
||||
}
|
||||
|
||||
void light_switch_unlock(light_switch *current_light_switch, sem_t *current_semaphore){
|
||||
sem_wait(¤t_light_switch->mutex);
|
||||
current_light_switch->counter--;
|
||||
|
||||
if(current_light_switch->counter == 0){
|
||||
sem_post(current_semaphore);
|
||||
}
|
||||
|
||||
sem_post(¤t_light_switch->mutex);
|
||||
}
|
||||
|
||||
void *inserter_thread(){
|
||||
printf("Inserter starting.\n");
|
||||
fflush(stdout);
|
||||
|
||||
sleep(2); //Do this so you can easily see threads starting
|
||||
|
||||
while(1){
|
||||
uint16_t new_number = get_random_number(MIN_NUMBER, MAX_NUMBER);
|
||||
uint16_t sleep_time = get_random_number(MIN_SLEEP_INSERTER, MAX_SLEEP_INSERTER);
|
||||
|
||||
printf("Inserter going to sleep for %d seconds.\n", sleep_time);
|
||||
fflush(stdout);
|
||||
sleep(sleep_time);
|
||||
|
||||
printf("Inserter awake and waiting for access.\n");
|
||||
fflush(stdout);
|
||||
light_switch_lock(&insertion_light_switch, &no_insertions_semaphore);
|
||||
sem_wait(&insertion_mutex);
|
||||
|
||||
printf("Inserter now has access.\n");
|
||||
printf("Inserting number %u.\n", new_number);
|
||||
fflush(stdout);
|
||||
insert_linked_list(new_number);
|
||||
|
||||
sem_post(&insertion_mutex);
|
||||
light_switch_unlock(&insertion_light_switch, &no_insertions_semaphore);
|
||||
}
|
||||
}
|
||||
|
||||
void *searcher_thread(){
|
||||
printf("Searcher starting.\n");
|
||||
fflush(stdout);
|
||||
|
||||
sleep(2); //Do this so you can easily see threads starting
|
||||
|
||||
while(1){
|
||||
uint16_t search_value = get_random_number(MIN_NUMBER, MAX_NUMBER);
|
||||
uint16_t sleep_time = get_random_number(MIN_SLEEP_SEARCHER, MAX_SLEEP_SEARCHER);
|
||||
|
||||
printf("Searcher going to sleep for %d seconds.\n", sleep_time);
|
||||
fflush(stdout);
|
||||
sleep(sleep_time);
|
||||
|
||||
printf("Searcher awake and waiting for access.\n");
|
||||
fflush(stdout);
|
||||
light_switch_lock(&search_light_switch, &no_searches_semaphore);
|
||||
|
||||
printf("Searcher has access.\n");
|
||||
fflush(stdout);
|
||||
|
||||
int16_t value = position_of_value_linked_list(search_value);
|
||||
|
||||
if(value != -1){
|
||||
printf("Search successful. Found value %d.\n", value);
|
||||
} else {
|
||||
printf("Search unsuccessful. Could not find value %u.\n", search_value);
|
||||
}
|
||||
fflush(stdout);
|
||||
|
||||
light_switch_unlock(&search_light_switch, &no_searches_semaphore);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void *deleter_thread(){
|
||||
printf("Deleter starting.\n");
|
||||
fflush(stdout);
|
||||
|
||||
sleep(2); //Do this so you can easily see threads starting
|
||||
|
||||
while(1){
|
||||
uint16_t sleep_time = get_random_number(MIN_SLEEP_DELETER, MAX_SLEEP_DELETER);
|
||||
|
||||
printf("Deleter going to sleep for %d seconds.\n", sleep_time);
|
||||
fflush(stdout);
|
||||
sleep(sleep_time);
|
||||
|
||||
printf("Deleter awake and waiting for access.\n");
|
||||
fflush(stdout);
|
||||
sem_wait(&no_searches_semaphore);
|
||||
sem_wait(&no_insertions_semaphore);
|
||||
|
||||
uint16_t delete_position = get_random_number(0, list_size);
|
||||
|
||||
printf("Deleter has access.\n");
|
||||
printf("Deleting node at position %d.\n", delete_position);
|
||||
fflush(stdout);
|
||||
delete_position_from_linked_list(delete_position);
|
||||
|
||||
sem_post(&no_insertions_semaphore);
|
||||
sem_post(&no_searches_semaphore);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Storage for threads
|
||||
pthread_t inserters[NUM_INSERTERS];
|
||||
pthread_t searchers[NUM_INSERTERS];
|
||||
pthread_t deleters[NUM_INSERTERS];
|
||||
|
||||
// Initialize light switches
|
||||
sem_init(&insertion_light_switch.mutex, 1, 1);
|
||||
insertion_light_switch.counter = 0;
|
||||
|
||||
sem_init(&search_light_switch.mutex, 1, 1);
|
||||
search_light_switch.counter = 0;
|
||||
|
||||
// Initialize other semaphores and mutex
|
||||
sem_init(&no_insertions_semaphore, 1, 1);
|
||||
sem_init(&no_searches_semaphore, 1, 1);
|
||||
sem_init(&insertion_mutex, 1, 1);
|
||||
|
||||
// Spin up threads
|
||||
for(uint8_t i = 0 ; i < NUM_INSERTERS ; i++){
|
||||
pthread_create(&inserters[i], NULL, inserter_thread, NULL);
|
||||
}
|
||||
|
||||
for(uint8_t i = 0 ; i < NUM_SEARCHERS ; i++){
|
||||
pthread_create(&searchers[i], NULL, searcher_thread, NULL);
|
||||
}
|
||||
|
||||
for(uint8_t i = 0 ; i < NUM_DELETERS ; i++){
|
||||
pthread_create(&deleters[i], NULL, deleter_thread, NULL);
|
||||
}
|
||||
|
||||
// Wait for threads to join for completion.
|
||||
for(uint8_t i = 0 ; i < NUM_INSERTERS ; i++){
|
||||
pthread_join(inserters[i], NULL);
|
||||
}
|
||||
|
||||
for(uint8_t i = 0 ; i < NUM_SEARCHERS ; i++){
|
||||
pthread_join(searchers[i], NULL);
|
||||
}
|
||||
|
||||
for(uint8_t i = 0 ; i < NUM_DELETERS ; i++){
|
||||
pthread_join(deleters[i], NULL);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
Corwin Perren - Concurrency HW 3
|
||||
|
||||
To make this program on the os server, cd into this directory and run "make".
|
||||
|
||||
To run program1, type "./concurrency3_problem1" into the terminal and hit enter.
|
||||
To run program2, type "./concurrency3_problem2" into the terminal and hit enter.
|
||||
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* File: main.c
|
||||
* Author: caperren
|
||||
*
|
||||
* Created on June 1st, 2018
|
||||
*/
|
||||
#define _POSIX_C_SOURCE 199309L
|
||||
|
||||
#include "mt19937ar.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/param.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <time.h>
|
||||
|
||||
// Program defines you might want to change
|
||||
#define NUM_BARBERSHOP_WAITING_ROOM_CHAIRS 5
|
||||
|
||||
// Program defines that don't get changed
|
||||
#define NUM_CUSTOMER_THREADS (NUM_BARBERSHOP_WAITING_ROOM_CHAIRS * 2)
|
||||
|
||||
#define MIN_RANDOM_WAIT_CUSTOMER_RESPAWN 4
|
||||
#define MAX_RANDOM_WAIT_CUSTOMER_RESPAWN 8
|
||||
|
||||
#define MIN_RANDOM_HAIRCUT_TIME 2
|
||||
#define MAX_RANDOM_HAIRCUT_TIME 4
|
||||
|
||||
//RDRAND value to check for
|
||||
#define RDRAND_FLAG (1 << 30)
|
||||
|
||||
// Global Variables
|
||||
sem_t waiting_room_chairs_semaphore;
|
||||
sem_t ticket_dispenser_semaphore;
|
||||
sem_t barber_chair_semaphore;
|
||||
|
||||
uint16_t current_ticket_number = 1;
|
||||
uint16_t barber_servicing_ticket = 0;
|
||||
|
||||
uint8_t haircut_started = 0;
|
||||
uint8_t haircut_over = 0;
|
||||
|
||||
struct timespec thread_sleep_time;
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Get random number based on whether rdrand is supported.
|
||||
uint8_t get_random_number(uint8_t min, uint8_t max) {
|
||||
uint8_t rand_val;
|
||||
unsigned long seed;
|
||||
|
||||
unsigned int eax;
|
||||
unsigned int ebx;
|
||||
unsigned int ecx;
|
||||
unsigned int edx;
|
||||
|
||||
eax = 0x01;
|
||||
|
||||
// ASM for checking if RDRAND supported
|
||||
__asm__ __volatile__("cpuid"
|
||||
: "=a" (eax),
|
||||
"=b" (ebx),
|
||||
"=c" (ecx),
|
||||
"=d" (edx)
|
||||
: "a" (1),
|
||||
"c" (0)
|
||||
);
|
||||
|
||||
// Seed random with /dev/random
|
||||
int random = open("/dev/random", O_RDONLY);
|
||||
read(random, &seed, sizeof (seed));
|
||||
|
||||
unsigned int random_value;
|
||||
|
||||
if ((ecx & RDRAND_FLAG) == RDRAND_FLAG) {
|
||||
char return_code = 0;
|
||||
char count = 0;
|
||||
|
||||
// ASM for RDRAND
|
||||
while(return_code != 1 && count < 10){
|
||||
__asm__ volatile(
|
||||
"rdrand %0 ; setc %1"
|
||||
: "=r" (random_value), "=qm" (return_code)
|
||||
);
|
||||
|
||||
count++;
|
||||
}
|
||||
} else {
|
||||
// Twister if RDRAND not supported
|
||||
init_genrand(seed);
|
||||
random_value = genrand_int32();
|
||||
}
|
||||
|
||||
return (random_value % (max + 1 - min)) + min;
|
||||
}
|
||||
|
||||
void get_hair_cut(uint16_t customer_thread_id, uint16_t ticket_id){
|
||||
|
||||
while(!haircut_started){
|
||||
nanosleep(&thread_sleep_time, NULL);
|
||||
}
|
||||
|
||||
printf("Customer heading to barbers chair with ticket number %u.\n", ticket_id);
|
||||
fflush(stdout);
|
||||
|
||||
sem_wait(&barber_chair_semaphore);
|
||||
|
||||
printf("Customer with thread id %u and ticket number %u sat down and getting haircut.\n", customer_thread_id, ticket_id);
|
||||
fflush(stdout);
|
||||
|
||||
while(!haircut_over){
|
||||
nanosleep(&thread_sleep_time, NULL);
|
||||
}
|
||||
|
||||
sem_post(&barber_chair_semaphore);
|
||||
|
||||
}
|
||||
|
||||
void cut_hair(){
|
||||
uint16_t sleep_time = get_random_number(MIN_RANDOM_HAIRCUT_TIME, MAX_RANDOM_HAIRCUT_TIME);
|
||||
int customer_in_chair = 1;
|
||||
|
||||
haircut_over = 0;
|
||||
haircut_started = 1;
|
||||
|
||||
printf("Barber waiting for customer to sit down with ticket number %d.\n", barber_servicing_ticket);
|
||||
fflush(stdout);
|
||||
while(customer_in_chair > 0){
|
||||
sem_getvalue(&barber_chair_semaphore, &customer_in_chair);
|
||||
nanosleep(&thread_sleep_time, NULL);
|
||||
|
||||
}
|
||||
|
||||
printf("Barber giving haircut to ticket number %d for %d seconds.\n", barber_servicing_ticket, sleep_time);
|
||||
fflush(stdout);
|
||||
|
||||
sleep(sleep_time);
|
||||
|
||||
haircut_started = 0;
|
||||
haircut_over = 1;
|
||||
|
||||
while(customer_in_chair <= 0){
|
||||
sem_getvalue(&barber_chair_semaphore, &customer_in_chair);
|
||||
nanosleep(&thread_sleep_time, NULL);
|
||||
}
|
||||
|
||||
printf("Barber finished haircut for ticket number %d.\n", barber_servicing_ticket);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
// If waiting room is empty, sleep until woken up by customer
|
||||
// If customer, cut_hair
|
||||
void *barber(){
|
||||
printf("Barber thread started.\n");
|
||||
fflush(stdout);
|
||||
|
||||
int used_waiting_room_chairs = 0;
|
||||
|
||||
while(1){
|
||||
// Check if anyone is in the waiting room
|
||||
sem_getvalue(&waiting_room_chairs_semaphore, &used_waiting_room_chairs);
|
||||
|
||||
if(used_waiting_room_chairs == 5){
|
||||
nanosleep(&thread_sleep_time, NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Tell customers next ticket number
|
||||
barber_servicing_ticket++;
|
||||
|
||||
// Service the customer
|
||||
cut_hair();
|
||||
}
|
||||
}
|
||||
|
||||
// If the waiting room is full, customer leaves
|
||||
// If waiting room has empty chair, sits in chair, unless barber is ready
|
||||
// When ready, sits in chair and runs get_hair_cut, then leaves
|
||||
void *customer(void *thread_id_number){
|
||||
uint16_t thread_id = *((uint16_t *)thread_id_number);
|
||||
|
||||
printf("Customer thread with id %d started.\n", thread_id);
|
||||
fflush(stdout);
|
||||
|
||||
int used_waiting_room_chairs = 0;
|
||||
uint16_t customer_ticket_number = 0;
|
||||
|
||||
while(1){
|
||||
// Wait before deciding to enter store
|
||||
uint16_t sleep_time = get_random_number(MIN_RANDOM_WAIT_CUSTOMER_RESPAWN, MAX_RANDOM_WAIT_CUSTOMER_RESPAWN);
|
||||
sleep(sleep_time);
|
||||
|
||||
// Check if seats are full, exit store if full
|
||||
sem_getvalue(&waiting_room_chairs_semaphore, &used_waiting_room_chairs);
|
||||
|
||||
if(used_waiting_room_chairs == 0){
|
||||
printf("Customer thread with id %d entered store, but was full. Leaving.\n", thread_id);
|
||||
fflush(stdout);
|
||||
continue;
|
||||
}
|
||||
|
||||
// There's space in the waiting room, take a seat and a number
|
||||
sem_wait(&waiting_room_chairs_semaphore);
|
||||
sem_wait(&ticket_dispenser_semaphore);
|
||||
customer_ticket_number = current_ticket_number;
|
||||
current_ticket_number++;
|
||||
sem_post(&ticket_dispenser_semaphore);
|
||||
|
||||
printf("Customer thread with id %d has ticket number %u.\n", thread_id, current_ticket_number);
|
||||
fflush(stdout);
|
||||
|
||||
// Wait until our number is called
|
||||
while(barber_servicing_ticket != customer_ticket_number){
|
||||
nanosleep(&thread_sleep_time, NULL);
|
||||
}
|
||||
|
||||
// It's time for a haircut, give up our seat in the waiting room
|
||||
sem_post(&waiting_room_chairs_semaphore);
|
||||
|
||||
// Get a haircut
|
||||
get_hair_cut(thread_id, customer_ticket_number);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Setup thread sleep variable
|
||||
thread_sleep_time.tv_nsec = 10000000;
|
||||
thread_sleep_time.tv_sec = 0;
|
||||
|
||||
// Storage for threads
|
||||
pthread_t barber_thread;
|
||||
pthread_t potential_customers_threads[NUM_CUSTOMER_THREADS];
|
||||
uint16_t customers_thread_ids[NUM_CUSTOMER_THREADS];
|
||||
|
||||
|
||||
// Initialize semaphores
|
||||
sem_init(&waiting_room_chairs_semaphore, 1, NUM_BARBERSHOP_WAITING_ROOM_CHAIRS);
|
||||
sem_init(&ticket_dispenser_semaphore, 1, 1);
|
||||
sem_init(&barber_chair_semaphore, 1, 1);
|
||||
|
||||
// Start barber thread
|
||||
pthread_create(&barber_thread, NULL, barber, NULL);
|
||||
|
||||
// Start potential custom threads
|
||||
for(uint16_t i = 0 ; i < NUM_CUSTOMER_THREADS ; i++){
|
||||
customers_thread_ids[i] = i;
|
||||
pthread_create(&potential_customers_threads[i], NULL, customer, &customers_thread_ids[i]);
|
||||
}
|
||||
|
||||
// Wait for barber thread to finish
|
||||
pthread_join(barber_thread, NULL);
|
||||
|
||||
// Wait for customer threads to finish
|
||||
for(uint8_t i = 0 ; i < NUM_CUSTOMER_THREADS ; i++){
|
||||
pthread_join(potential_customers_threads[i], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
all: clean build
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
rm -f concurrency4
|
||||
|
||||
build:
|
||||
gcc main.c mt19937ar.h -o concurrency4 -std=c99 -lpthread -lrt
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
A C-program for MT19937, with initialization improved 2002/1/26.
|
||||
Coded by Takuji Nishimura and Makoto Matsumoto.
|
||||
|
||||
Before using, initialize the state by using init_genrand(seed)
|
||||
or init_by_array(init_key, key_length).
|
||||
|
||||
Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of its contributors may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
Any feedback is very welcome.
|
||||
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
|
||||
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Period parameters */
|
||||
#define N 624
|
||||
#define M 397
|
||||
#define MATRIX_A 0x9908b0dfUL /* constant vector a */
|
||||
#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
|
||||
#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
|
||||
|
||||
static unsigned long mt[N]; /* the array for the state vector */
|
||||
static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */
|
||||
|
||||
/* initializes mt[N] with a seed */
|
||||
void init_genrand(unsigned long s)
|
||||
{
|
||||
mt[0]= s & 0xffffffffUL;
|
||||
for (mti=1; mti<N; mti++) {
|
||||
mt[mti] =
|
||||
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
|
||||
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
|
||||
/* In the previous versions, MSBs of the seed affect */
|
||||
/* only MSBs of the array mt[]. */
|
||||
/* 2002/01/09 modified by Makoto Matsumoto */
|
||||
mt[mti] &= 0xffffffffUL;
|
||||
/* for >32 bit machines */
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize by an array with array-length */
|
||||
/* init_key is the array for initializing keys */
|
||||
/* key_length is its length */
|
||||
/* slight change for C++, 2004/2/26 */
|
||||
void init_by_array(unsigned long init_key[], int key_length)
|
||||
{
|
||||
int i, j, k;
|
||||
init_genrand(19650218UL);
|
||||
i=1; j=0;
|
||||
k = (N>key_length ? N : key_length);
|
||||
for (; k; k--) {
|
||||
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
|
||||
+ init_key[j] + j; /* non linear */
|
||||
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
|
||||
i++; j++;
|
||||
if (i>=N) { mt[0] = mt[N-1]; i=1; }
|
||||
if (j>=key_length) j=0;
|
||||
}
|
||||
for (k=N-1; k; k--) {
|
||||
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
|
||||
- i; /* non linear */
|
||||
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
|
||||
i++;
|
||||
if (i>=N) { mt[0] = mt[N-1]; i=1; }
|
||||
}
|
||||
|
||||
mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
|
||||
}
|
||||
|
||||
/* generates a random number on [0,0xffffffff]-interval */
|
||||
unsigned long genrand_int32(void)
|
||||
{
|
||||
unsigned long y;
|
||||
static unsigned long mag01[2]={0x0UL, MATRIX_A};
|
||||
/* mag01[x] = x * MATRIX_A for x=0,1 */
|
||||
|
||||
if (mti >= N) { /* generate N words at one time */
|
||||
int kk;
|
||||
|
||||
if (mti == N+1) /* if init_genrand() has not been called, */
|
||||
init_genrand(5489UL); /* a default initial seed is used */
|
||||
|
||||
for (kk=0;kk<N-M;kk++) {
|
||||
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
||||
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
}
|
||||
for (;kk<N-1;kk++) {
|
||||
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
||||
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
}
|
||||
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
|
||||
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
|
||||
mti = 0;
|
||||
}
|
||||
|
||||
y = mt[mti++];
|
||||
|
||||
/* Tempering */
|
||||
y ^= (y >> 11);
|
||||
y ^= (y << 7) & 0x9d2c5680UL;
|
||||
y ^= (y << 15) & 0xefc60000UL;
|
||||
y ^= (y >> 18);
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
/* generates a random number on [0,0x7fffffff]-interval */
|
||||
long genrand_int31(void)
|
||||
{
|
||||
return (long)(genrand_int32()>>1);
|
||||
}
|
||||
|
||||
/* generates a random number on [0,1]-real-interval */
|
||||
double genrand_real1(void)
|
||||
{
|
||||
return genrand_int32()*(1.0/4294967295.0);
|
||||
/* divided by 2^32-1 */
|
||||
}
|
||||
|
||||
/* generates a random number on [0,1)-real-interval */
|
||||
double genrand_real2(void)
|
||||
{
|
||||
return genrand_int32()*(1.0/4294967296.0);
|
||||
/* divided by 2^32 */
|
||||
}
|
||||
|
||||
/* generates a random number on (0,1)-real-interval */
|
||||
double genrand_real3(void)
|
||||
{
|
||||
return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0);
|
||||
/* divided by 2^32 */
|
||||
}
|
||||
|
||||
/* generates a random number on [0,1) with 53-bit resolution*/
|
||||
double genrand_res53(void)
|
||||
{
|
||||
unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6;
|
||||
return(a*67108864.0+b)*(1.0/9007199254740992.0);
|
||||
}
|
||||
/* These real versions are due to Isaku Wada, 2002/01/09 added */
|
||||
|
||||
//int main(void)
|
||||
//{
|
||||
// int i;
|
||||
// unsigned long init[4]={0x123, 0x234, 0x345, 0x456}, length=4;
|
||||
// init_by_array(init, length);
|
||||
// printf("1000 outputs of genrand_int32()\n");
|
||||
// for (i=0; i<1000; i++) {
|
||||
// printf("%10lu ", genrand_int32());
|
||||
// if (i%5==4) printf("\n");
|
||||
// }
|
||||
// printf("\n1000 outputs of genrand_real2()\n");
|
||||
// for (i=0; i<1000; i++) {
|
||||
// printf("%10.8f ", genrand_real2());
|
||||
// if (i%5==4) printf("\n");
|
||||
// }
|
||||
// return 0;
|
||||
//}
|
||||
@@ -0,0 +1,11 @@
|
||||
Corwin Perren - Concurrency HW 4
|
||||
|
||||
To make this program on the os server, cd into this directory and run "make".
|
||||
|
||||
To run, type "./concurrency4" into the terminal.
|
||||
|
||||
To change the number of chairs in the shop, edit the line in main.c, seen below,
|
||||
to have the number of desired waiting room chairs.
|
||||
|
||||
#define NUM_BARBERSHOP_WAITING_ROOM_CHAIRS 5
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
||||
\section{Commands}
|
||||
\begin{itemize}
|
||||
\item mkdir /scratch/spring2018/4
|
||||
\item cd /scratch/spring20128/4
|
||||
\item git init
|
||||
\item wget http://git.yoctoproject.org/cgit.cgi/linux-yocto/snapshot/linux-yocto-3.19.2.tar.bz2
|
||||
\item tar xvjf linux-yocto-3.19.2.tar.bz2
|
||||
\item cp /scratch/files/bzImage-qemux86.bin .
|
||||
\item cp /scratch/files/core-image-lsb-sdk-qemux86.ext4 .
|
||||
\item cp /scratch/files/config-3.19.2-yocto-standard .config
|
||||
\item source /scratch/files/environment-setup-i586-poky-linux.csh
|
||||
\item make -j4
|
||||
\item qemu-system-i386 -gdb tcp::5004 -nographic -kernel bzImage-qemux86.bin -drive file=core-image-lsb-sdk-qemux86.ext4,if=virtio -enable-kvm -net none -usb -localtime --no-reboot --append "root=/dev/vda rw console=ttyS0 debug".
|
||||
|
||||
\end{itemize}
|
||||
@@ -0,0 +1,53 @@
|
||||
\section{QEMU Flags}
|
||||
|
||||
\begin{itemize}
|
||||
\item \texttt{-gdb tcp::????}
|
||||
|
||||
Waits for a GDB connection on the specified device, namely a TCP
|
||||
connection on port ????.
|
||||
|
||||
\item \texttt{-S}
|
||||
|
||||
Prevents the CPU from starting up when first launching the command.
|
||||
|
||||
\item \texttt{-nographic}
|
||||
|
||||
Disables graphical capabilities and turns qemu into a command line
|
||||
application.
|
||||
|
||||
\item \texttt{-kernel bzImage-qemux86.bin}
|
||||
|
||||
Uses the ``\texttt{bzImage-qemux86.bin}'' binary as the kernel image to boot.
|
||||
|
||||
\item \texttt{-drive file=core-image-lsb-sdk-qemux86.ext4,if=virtio}
|
||||
|
||||
Uses ``\texttt{core-image-lsb-sdk-qemux86.ext4}'' as the file for the virtual
|
||||
hard drive, and virtio as the I/O interface (virtio virtualizes I/O
|
||||
operations like disk reads/writes).
|
||||
|
||||
\item \texttt{-enable-kvm}
|
||||
|
||||
Enables use of kernel-based virtual machine technology.
|
||||
|
||||
\item \texttt{-net none}
|
||||
|
||||
Indicates that no network devices should be configured.
|
||||
|
||||
\item \texttt{-usb}
|
||||
|
||||
Enables USB drivers.
|
||||
|
||||
\item \texttt{-localtime}
|
||||
|
||||
Uses the local time from the host machine to set the time in the guest,
|
||||
instead of the default of UTC time.
|
||||
|
||||
\item \texttt{--no-reboot}
|
||||
|
||||
Shuts down the guest entirely on exit instead of rebooting.
|
||||
|
||||
\item \texttt{--append "root=/dev/vda rw console=ttyS0 debug"}
|
||||
|
||||
Uses \texttt{"root=/dev/vda rw console=ttyS0 debug"} as the initial command line,
|
||||
running it on initial boot.
|
||||
\end{itemize}
|
||||
@@ -0,0 +1,107 @@
|
||||
\documentclass[onecolumn, draftclsnofoot, 10pt, compsoc]{IEEEtran}
|
||||
\usepackage{graphicx}
|
||||
\graphicspath{{./figures/}}
|
||||
|
||||
\usepackage{url}
|
||||
\usepackage{setspace}
|
||||
\usepackage{multicol}
|
||||
\usepackage{pdflscape}
|
||||
\usepackage{pdfpages}
|
||||
\usepackage[british]{babel}
|
||||
\usepackage{listings}
|
||||
\usepackage{xcolor}
|
||||
\usepackage{listings}
|
||||
\usepackage{hyperref}
|
||||
\usepackage{subfig}
|
||||
|
||||
\usepackage{geometry}
|
||||
\geometry{textheight=9.5in, textwidth=7in}
|
||||
|
||||
% \overfullrule=2in
|
||||
|
||||
|
||||
%Personal \newcommands
|
||||
|
||||
\definecolor{backcolor}{rgb}{0.95,0.95,0.92}
|
||||
\lstset{basicstyle=\ttfamily,
|
||||
backgroundcolor=\color{backcolor},
|
||||
showstringspaces=false,
|
||||
commentstyle=\color{red},
|
||||
keywordstyle=\color{blue},
|
||||
columns=fullflexible,
|
||||
breaklines=true,
|
||||
postbreak=\mbox{\textcolor{red}{$\hookrightarrow$}\space},
|
||||
}
|
||||
|
||||
\newcommand{\NameSigPair}[1]{
|
||||
\par
|
||||
\makebox[2.75in][r]{#1}
|
||||
\hfill
|
||||
\makebox[3.25in]{
|
||||
\makebox[2.25in]{\hrulefill}
|
||||
\hfill
|
||||
\makebox[.75in]{\hrulefill}
|
||||
}
|
||||
\par\vspace{-12pt}
|
||||
\textit{
|
||||
\tiny\noindent
|
||||
\makebox[2.75in]{}
|
||||
\hfill
|
||||
\makebox[3.25in]{
|
||||
\makebox[2.25in][r]{Signature}
|
||||
\hfill
|
||||
\makebox[.75in][r]{Date}
|
||||
}
|
||||
}
|
||||
}
|
||||
% 3. If the document is not to be signed, uncomment the command below
|
||||
\renewcommand{\NameSigPair}[1]{#1}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\begin{document}
|
||||
\begin{titlepage}
|
||||
\pagenumbering{gobble}
|
||||
\begin{singlespace}
|
||||
\par\vspace{2in}
|
||||
\centering
|
||||
\scshape{
|
||||
\huge Operating Systems II Homework 1 \par
|
||||
{\large\today}\par
|
||||
\vspace{.5in}
|
||||
\vfill
|
||||
\vspace{5pt}
|
||||
{\large Prepared by }\par
|
||||
Group 4 \par
|
||||
% 5. comment out the line below this one if you do not wish to name your team
|
||||
\vspace{5pt}
|
||||
{\Large
|
||||
\NameSigPair{Corinna Brown}\par
|
||||
\NameSigPair{Zachary Comito}\par
|
||||
\NameSigPair{Corwin Perren}\par
|
||||
}
|
||||
\vspace{20pt}
|
||||
\begin{abstract}
|
||||
The document is our groups submission for homework one covering the commands our group ran to finish the assignment, descriptions of qemu flags, answers to explicit assignment questions, a version control log, and work log.
|
||||
|
||||
|
||||
\end{abstract}
|
||||
}
|
||||
\end{singlespace}
|
||||
\end{titlepage}
|
||||
\newpage
|
||||
\pagenumbering{arabic}
|
||||
\tableofcontents
|
||||
\clearpage
|
||||
|
||||
\input{commands}
|
||||
\input{flags}
|
||||
\input{questions}
|
||||
\input{versioncontrollog}
|
||||
\input{worklog}
|
||||
|
||||
\end{document}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,31 @@
|
||||
# This config is copied from overleaf so output there will match compiled output here
|
||||
|
||||
# support for the glossaries package:
|
||||
add_cus_dep('glo', 'gls', 0, 'makeglossaries');
|
||||
add_cus_dep('acn', 'acr', 0, 'makeglossaries');
|
||||
sub makeglossaries {
|
||||
system("makeglossaries \"$_[0]\"");
|
||||
}
|
||||
|
||||
# support for the nomencl package:
|
||||
add_cus_dep('nlo', 'nls', 0, 'makenlo2nls');
|
||||
sub makenlo2nls {
|
||||
system("makeindex -s nomencl.ist -o \"$_[0].nls\" \"$_[0].nlo\"");
|
||||
}
|
||||
|
||||
# from the documentation for V. 2.03 of asymptote:
|
||||
sub asy {return system("asy \"$_[0]\"");}
|
||||
add_cus_dep("asy","eps",0,"asy");
|
||||
add_cus_dep("asy","pdf",0,"asy");
|
||||
add_cus_dep("asy","tex",0,"asy");
|
||||
|
||||
# metapost rule from http://tex.stackexchange.com/questions/37134
|
||||
add_cus_dep('mp', '1', 0, 'mpost');
|
||||
sub mpost {
|
||||
my $file = $_[0];
|
||||
my ($name, $path) = fileparse($file);
|
||||
pushd($path);
|
||||
my $return = system "mpost $name";
|
||||
popd();
|
||||
return $return;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
# Makefile created by Corwin Perren
|
||||
# Generic makefile for all LaTeX projects downloaded from overleaf
|
||||
#
|
||||
# All this makefile does is call perl against latexmkrc, which is
|
||||
# the latex equivalent of make
|
||||
|
||||
LATEXMK_COMPILE_FLAGS = -cd -pdf homework1.tex
|
||||
LATEXMK_CLEAN_FLAGS = -c
|
||||
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
all: latexmk_output clean
|
||||
|
||||
latexmk_output:
|
||||
perl latexmk.pl $(LATEXMK_COMPILE_FLAGS)
|
||||
mv homework1.pdf CS444_project1_4.pdf
|
||||
|
||||
clean:
|
||||
perl latexmk.pl $(LATEXMK_CLEAN_FLAGS)
|
||||
@@ -0,0 +1,12 @@
|
||||
\section{Questions}
|
||||
\subsection{Point of Assignment}
|
||||
The point of this assignment was to make sure that our group could properly get the course's development environment up and running. Additionally, it gave us initial experience with using qemu, as that will be a core tool used during this class. Setting up the git repository also was needed to ensure both the instructors and our group can keep track of changes made to the kernel as we work on assignments over the term.
|
||||
|
||||
\subsection{Problem Approach}
|
||||
We approached this problem by systematically following the directions on the homework page, and making adjustments as necessary to fit our particular development environment. Where needed, we also looked up documentation through man pages and the internet.
|
||||
|
||||
\subsection{Correctness}
|
||||
We know that the end result was correct as we were able to successfully compile the kernel and boot the kernel in the emulator.
|
||||
|
||||
\subsection{What Was Learned}
|
||||
We learned how to set up the environment needed to both build and run a custom modified linux kernel in a virtual machine.
|
||||
@@ -0,0 +1,10 @@
|
||||
\section{Version Control Log}
|
||||
\begin{center}
|
||||
\begin{tabular}{l l l l} \textbf{Detail} & \textbf{Author} & \textbf{Date} &\textbf{Description}\\\hline
|
||||
|
||||
\href{commit/c52f73e00546af6f3fe60b23584aeb9c598db667}{c52f73e} & Corwin Perren & 2018-04-09 17:39:17 -0700 &Added initial kernel to our group folder.\\\hline
|
||||
\href{commit/974b4529f98f277120295937f6491675832c97bc}{974b452} & Corwin Perren & 2018-04-09 18:48:36 -0700 &Initial commit after first build\\\hline
|
||||
|
||||
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
@@ -0,0 +1,11 @@
|
||||
\section{Work Log}
|
||||
\begin{itemize}
|
||||
\item 2018-04-09
|
||||
\begin{itemize}
|
||||
\item Group met in valley library
|
||||
\item Set up initial os2 server workspace
|
||||
\item Ran make on kernel for first time
|
||||
\item Booted virtual machine for first time
|
||||
\item Wrote latex document for homework 1
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,27 @@
|
||||
\section{Design}
|
||||
\begin{itemize}
|
||||
\item Elevator: LOOK
|
||||
\item Method of sorting items: Insertion Sort
|
||||
\end{itemize}
|
||||
|
||||
The framework for the LOOK elevator was taken from the no-op elevator. To adapt this framework into the LOOK elevator, the "sstf\_add\_request" function was changed so that each item is sorted as it is inserted into the queue rather than simply adding each new request to the end of the queue. The following is pseudocode that describes the "sstf\_add\_request" function.
|
||||
|
||||
\begin{lstlisting}[lineskip=3pt,keywords={if,else,while}]
|
||||
if (list is empty) {
|
||||
add request to queue
|
||||
}
|
||||
else {
|
||||
if (request > next) {
|
||||
while (request > next) {
|
||||
move up the queue
|
||||
}
|
||||
add request to queue before this point
|
||||
}
|
||||
else {
|
||||
while (request > prev) {
|
||||
move down the queue
|
||||
}
|
||||
add request to queue after this point
|
||||
}
|
||||
}
|
||||
\end{lstlisting}
|
||||
@@ -0,0 +1,278 @@
|
||||
diff -Naur '--exclude=*.o*' '--exclude=*.ko' '--exclude=*.builtin' linux-yocto-3.19.2_untouched/block/Kconfig.iosched linux-yocto-3.19.2/block/Kconfig.iosched
|
||||
--- linux-yocto-3.19.2_untouched/block/Kconfig.iosched 2018-05-04 15:14:42.027042321 -0700
|
||||
+++ linux-yocto-3.19.2/block/Kconfig.iosched 2018-05-04 19:08:10.346278748 -0700
|
||||
@@ -32,6 +32,12 @@
|
||||
|
||||
This is the default I/O scheduler.
|
||||
|
||||
+config IOSCHED_SSTF
|
||||
+ tristate "SSTF scheduler"
|
||||
+ default y
|
||||
+ ---help---
|
||||
+ SSTF for class
|
||||
+
|
||||
config CFQ_GROUP_IOSCHED
|
||||
bool "CFQ Group Scheduling support"
|
||||
depends on IOSCHED_CFQ && BLK_CGROUP
|
||||
@@ -55,6 +61,9 @@
|
||||
config DEFAULT_NOOP
|
||||
bool "No-op"
|
||||
|
||||
+ config DEFAULT_SSTF
|
||||
+ bool "SSTF" if IOSCHED_SSTF=y
|
||||
+
|
||||
endchoice
|
||||
|
||||
config DEFAULT_IOSCHED
|
||||
@@ -62,7 +71,7 @@
|
||||
default "deadline" if DEFAULT_DEADLINE
|
||||
default "cfq" if DEFAULT_CFQ
|
||||
default "noop" if DEFAULT_NOOP
|
||||
-
|
||||
+ default "sstf" if DEFAULT_SSTF
|
||||
endmenu
|
||||
|
||||
endif
|
||||
diff -Naur '--exclude=*.o*' '--exclude=*.ko' '--exclude=*.builtin' linux-yocto-3.19.2_untouched/block/Makefile linux-yocto-3.19.2/block/Makefile
|
||||
--- linux-yocto-3.19.2_untouched/block/Makefile 2018-05-04 15:14:42.055042785 -0700
|
||||
+++ linux-yocto-3.19.2/block/Makefile 2018-05-04 17:41:20.460575829 -0700
|
||||
@@ -18,8 +18,7 @@
|
||||
obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o
|
||||
obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o
|
||||
obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o
|
||||
-
|
||||
+obj-$(CONFIG_IOSCHED_SSTF) += sstf-iosched.o
|
||||
obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o
|
||||
obj-$(CONFIG_BLK_CMDLINE_PARSER) += cmdline-parser.o
|
||||
obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o blk-integrity.o t10-pi.o
|
||||
-
|
||||
diff -Naur '--exclude=*.o*' '--exclude=*.ko' '--exclude=*.builtin' linux-yocto-3.19.2_untouched/block/sstf-iosched.c linux-yocto-3.19.2/block/sstf-iosched.c
|
||||
--- linux-yocto-3.19.2_untouched/block/sstf-iosched.c 1969-12-31 16:00:00.000000000 -0800
|
||||
+++ linux-yocto-3.19.2/block/sstf-iosched.c 2018-05-05 16:33:00.528490307 -0700
|
||||
@@ -0,0 +1,226 @@
|
||||
+/* Developed by Corwin Perren and Corinna Brown
|
||||
+ * Date: May 4, 2018
|
||||
+ * Name: sstf-iosched.c
|
||||
+ */
|
||||
+#include <linux/blkdev.h>
|
||||
+#include <linux/elevator.h>
|
||||
+#include <linux/bio.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/init.h>
|
||||
+
|
||||
+//Main data type to store requests
|
||||
+struct sstf_data{
|
||||
+ struct list_head queue;
|
||||
+ int dir;
|
||||
+ sector_t head;
|
||||
+};
|
||||
+
|
||||
+/* Name: sstf_merge_requests
|
||||
+ * Description: merges requests
|
||||
+ * Parameters: request queue, request, next node
|
||||
+ */
|
||||
+static void sstf_merge_requests(struct request_queue *queue,
|
||||
+ struct request *req, struct request *next)
|
||||
+{
|
||||
+ list_del_init(&next->queuelist);
|
||||
+}
|
||||
+
|
||||
+/* Name: sstf_dispatch
|
||||
+ * Description: Main portion of code, runs the actual elevator
|
||||
+ * Parameters: request queue, force
|
||||
+ */
|
||||
+static int sstf_dispatch(struct request_queue *queue, int force)
|
||||
+{
|
||||
+ struct sstf_data *nd = queue->elevator->elevator_data;
|
||||
+
|
||||
+ if (!list_empty(&nd->queue)){
|
||||
+ struct request *req;
|
||||
+ req = list_entry(nd->queue.next, struct request, queuelist);
|
||||
+ list_del_init(&req->queuelist);
|
||||
+ elv_dispatch_sort(queue, req);
|
||||
+ printk(KERN_DEBUG "[SSTF_GROUP4] Dispatching: %s at %lu\n",
|
||||
+ (rq_data_dir(req)) == READ ? "READ": "WRITE",
|
||||
+ (long unsigned int) blk_rq_pos(req));
|
||||
+
|
||||
+ return 1;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Name: sstf_add_request
|
||||
+ * Description: adds a request to the queue
|
||||
+ * Parameters: Request queue, request
|
||||
+ */
|
||||
+static void sstf_add_request(struct request_queue *queue, struct request *req)
|
||||
+{
|
||||
+ struct sstf_data *nd = queue->elevator->elevator_data;
|
||||
+ struct request *next, *prev;
|
||||
+ struct request *iter;
|
||||
+
|
||||
+ // If the list is empty, we simply add it to the queue.
|
||||
+ if (list_empty(&nd->queue)){
|
||||
+ printk(KERN_DEBUG "[SSTF_GROUP4] Adding %s at %lu\n",
|
||||
+ (rq_data_dir(req)) == READ ? "READ": "WRITE",
|
||||
+ (long unsigned int) blk_rq_pos(req));
|
||||
+
|
||||
+ list_add(&req->queuelist, &nd->queue);
|
||||
+
|
||||
+ // Otherwise we'll need to find the right place to insert the request
|
||||
+ } else {
|
||||
+ // Get the next and previous entries from the queue
|
||||
+ next = list_entry(nd->queue.next, struct request, queuelist);
|
||||
+ prev = list_entry(nd->queue.prev, struct request, queuelist);
|
||||
+
|
||||
+ // If the request is larger than the "next" item, work UP the queue
|
||||
+ // until this isn't the case, and insert it directly before this point
|
||||
+ if (blk_rq_pos(req) > blk_rq_pos(next)){
|
||||
+ while (blk_rq_pos(req) > blk_rq_pos(next)) {
|
||||
+ prev = next;
|
||||
+ next = list_entry(next->queuelist.next, struct request,
|
||||
+ queuelist);
|
||||
+ }
|
||||
+ printk(KERN_DEBUG "[SSTF_GROUP4] Adding %s at %lu\n",
|
||||
+ (rq_data_dir(req)) == READ ? "READ": "WRITE",
|
||||
+ (long unsigned int) blk_rq_pos(req));
|
||||
+
|
||||
+ list_add(&req->queuelist, &prev->queuelist);
|
||||
+
|
||||
+ // Otherise, if the request is smaller than next, work DOWN the queue
|
||||
+ // unles this isn't the case, and insert direct after this point
|
||||
+ } else {
|
||||
+ while (blk_rq_pos(req) > blk_rq_pos(prev)) {
|
||||
+ next = prev;
|
||||
+ prev = list_entry(prev->queuelist.prev, struct request,
|
||||
+ queuelist);
|
||||
+ }
|
||||
+ printk(KERN_DEBUG "[SSTF_GROUP4] Adding %s at %lu\n",
|
||||
+ (rq_data_dir(req)) == READ ? "READ": "WRITE",
|
||||
+ (long unsigned int) blk_rq_pos(req));
|
||||
+
|
||||
+ list_add(&req->queuelist, &next->queuelist);
|
||||
+ }
|
||||
+
|
||||
+ // Prints out entries in queue, for verification
|
||||
+ printk(KERN_DEBUG "[SSTF_GROUP4] Priting current queue:\n");
|
||||
+ list_for_each_entry(iter, &nd->queue, queuelist) {
|
||||
+ printk(KERN_DEBUG "[SSTF_GROUP4] Item: %lu\n",
|
||||
+ (unsigned long) blk_rq_pos(iter));
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Name: sstf_former_request
|
||||
+ * Description: stores former request in queue
|
||||
+ * Parameters: request queue, request
|
||||
+ */
|
||||
+static struct request *sstf_former_request(struct request_queue *queue,
|
||||
+ struct request *req)
|
||||
+{
|
||||
+ struct sstf_data *data = queue->elevator->elevator_data;
|
||||
+
|
||||
+ if(req->queuelist.prev == &data->queue)
|
||||
+ return NULL;
|
||||
+
|
||||
+ return list_entry(req->queuelist.prev, struct request, queuelist);
|
||||
+}
|
||||
+
|
||||
+/* Name: sstf_latter_request
|
||||
+ * Description: stores latter request in queue
|
||||
+ * Parameters: request queue, request
|
||||
+ */
|
||||
+static struct request *sstf_latter_request(struct request_queue *queue,
|
||||
+ struct request *req)
|
||||
+{
|
||||
+ struct sstf_data *data = queue->elevator->elevator_data;
|
||||
+
|
||||
+ if(req->queuelist.next == &data->queue)
|
||||
+ return NULL;
|
||||
+
|
||||
+ return list_entry(req->queuelist.next, struct request, queuelist);
|
||||
+}
|
||||
+
|
||||
+/* Name: sstf_init_queue
|
||||
+ * Description: Initializes the queue
|
||||
+ * Parameters: Request queue, Elevator
|
||||
+ */
|
||||
+static int sstf_init_queue(struct request_queue *queue,
|
||||
+ struct elevator_type *elev)
|
||||
+{
|
||||
+ struct sstf_data *data;
|
||||
+ struct elevator_queue *elevque;
|
||||
+
|
||||
+ elevque = elevator_alloc(queue, elev);
|
||||
+
|
||||
+ if(!elevque)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ data = kmalloc_node(sizeof(*data), GFP_KERNEL, queue->node);
|
||||
+
|
||||
+ if(!data){
|
||||
+ kobject_put(&elevque->kobj);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ data->head = 0;
|
||||
+ elevque->elevator_data = data;
|
||||
+
|
||||
+ INIT_LIST_HEAD(&data->queue);
|
||||
+
|
||||
+ spin_lock_irq(queue->queue_lock);
|
||||
+ queue->elevator = elevque;
|
||||
+ spin_unlock_irq(queue->queue_lock);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Name: sstf_exit_queue
|
||||
+ * Description: exits the queue
|
||||
+ * Parameters: elevator
|
||||
+ */
|
||||
+static void sstf_exit_queue(struct elevator_queue *elev)
|
||||
+{
|
||||
+ struct sstf_data *data = elev->elevator_data;
|
||||
+
|
||||
+ BUG_ON(!list_empty(&data->queue));
|
||||
+ kfree(data);
|
||||
+}
|
||||
+
|
||||
+static struct elevator_type elevator_sstf = {
|
||||
+ .ops = {
|
||||
+ .elevator_init_fn = sstf_init_queue,
|
||||
+ .elevator_add_req_fn = sstf_add_request,
|
||||
+ .elevator_former_req_fn = sstf_former_request,
|
||||
+ .elevator_latter_req_fn = sstf_latter_request,
|
||||
+ .elevator_merge_req_fn = sstf_merge_requests,
|
||||
+ .elevator_dispatch_fn = sstf_dispatch,
|
||||
+ .elevator_exit_fn = sstf_exit_queue,
|
||||
+ },
|
||||
+ .elevator_name = "sstf",
|
||||
+ .elevator_owner = THIS_MODULE,
|
||||
+};
|
||||
+
|
||||
+/* Name: elev_init
|
||||
+ * Description: Initializes the elevator
|
||||
+ * Parameters: N/A
|
||||
+ */
|
||||
+static int __init elev_init(void)
|
||||
+{
|
||||
+ return elv_register(&elevator_sstf);
|
||||
+}
|
||||
+
|
||||
+/* Name: elev_exit
|
||||
+ * Description: exits out of the elevator
|
||||
+ * Parameters: N/A
|
||||
+ */
|
||||
+static void __exit elev_exit(void)
|
||||
+{
|
||||
+ elv_unregister(&elevator_sstf);
|
||||
+}
|
||||
+
|
||||
+module_init(elev_init);
|
||||
+module_exit(elev_exit);
|
||||
+
|
||||
+MODULE_AUTHOR("Corwin Perren, Corinna Brown");
|
||||
+MODULE_LICENSE("GPL");
|
||||
+MODULE_DESCRIPTION("SSTF IO Scheduler");
|
||||
@@ -0,0 +1,105 @@
|
||||
\documentclass[onecolumn, draftclsnofoot, 10pt, compsoc]{IEEEtran}
|
||||
\usepackage{graphicx}
|
||||
\graphicspath{{./figures/}}
|
||||
|
||||
\usepackage{url}
|
||||
\usepackage{setspace}
|
||||
\usepackage{multicol}
|
||||
\usepackage{pdflscape}
|
||||
\usepackage{pdfpages}
|
||||
\usepackage[british]{babel}
|
||||
\usepackage{listings}
|
||||
\usepackage{xcolor}
|
||||
\usepackage{listings}
|
||||
\usepackage{hyperref}
|
||||
\usepackage{subfig}
|
||||
|
||||
\usepackage{geometry}
|
||||
\geometry{textheight=9.5in, textwidth=7in}
|
||||
|
||||
% \overfullrule=2in
|
||||
|
||||
|
||||
%Personal \newcommands
|
||||
|
||||
\definecolor{backcolor}{rgb}{0.95,0.95,0.92}
|
||||
\lstset{basicstyle=\ttfamily,
|
||||
backgroundcolor=\color{backcolor},
|
||||
showstringspaces=false,
|
||||
commentstyle=\color{red},
|
||||
keywordstyle=\color{blue},
|
||||
columns=fullflexible,
|
||||
breaklines=true,
|
||||
postbreak=\mbox{\textcolor{red}{$\hookrightarrow$}\space},
|
||||
}
|
||||
|
||||
\newcommand{\NameSigPair}[1]{
|
||||
\par
|
||||
\makebox[2.75in][r]{#1}
|
||||
\hfill
|
||||
\makebox[3.25in]{
|
||||
\makebox[2.25in]{\hrulefill}
|
||||
\hfill
|
||||
\makebox[.75in]{\hrulefill}
|
||||
}
|
||||
\par\vspace{-12pt}
|
||||
\textit{
|
||||
\tiny\noindent
|
||||
\makebox[2.75in]{}
|
||||
\hfill
|
||||
\makebox[3.25in]{
|
||||
\makebox[2.25in][r]{Signature}
|
||||
\hfill
|
||||
\makebox[.75in][r]{Date}
|
||||
}
|
||||
}
|
||||
}
|
||||
% 3. If the document is not to be signed, uncomment the command below
|
||||
\renewcommand{\NameSigPair}[1]{#1}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\begin{document}
|
||||
\begin{titlepage}
|
||||
\pagenumbering{gobble}
|
||||
\begin{singlespace}
|
||||
\par\vspace{2in}
|
||||
\centering
|
||||
\scshape{
|
||||
\huge Operating Systems II Homework 2 \par
|
||||
{\large\today}\par
|
||||
\vspace{.5in}
|
||||
\vfill
|
||||
\vspace{5pt}
|
||||
{\large Prepared by }\par
|
||||
Group 4 \par
|
||||
% 5. comment out the line below this one if you do not wish to name your team
|
||||
\vspace{5pt}
|
||||
{\Large
|
||||
\NameSigPair{Corinna Brown}\par
|
||||
\NameSigPair{Corwin Perren}\par
|
||||
}
|
||||
\vspace{20pt}
|
||||
\begin{abstract}
|
||||
The document is our groups submission for homework two covering the design of our solution, answers to explicit assignment questions, a version control log, and a work log.
|
||||
|
||||
|
||||
\end{abstract}
|
||||
}
|
||||
\end{singlespace}
|
||||
\end{titlepage}
|
||||
\newpage
|
||||
\pagenumbering{arabic}
|
||||
\tableofcontents
|
||||
\clearpage
|
||||
|
||||
\input{design}
|
||||
\input{questions}
|
||||
\input{versioncontrollog}
|
||||
\input{worklog}
|
||||
|
||||
\end{document}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import random
|
||||
import os, shutil
|
||||
|
||||
NUM_READ_WRITES = 10
|
||||
NUM_FILES = 100
|
||||
|
||||
RANDOM_PATH = "/dev/zero"
|
||||
dev_random = open(RANDOM_PATH, "r")
|
||||
|
||||
FILES_FOLDER = "files"
|
||||
|
||||
file_test_structure = {
|
||||
"file": None,
|
||||
"size": None
|
||||
}
|
||||
|
||||
ALL_FILES = []
|
||||
|
||||
if os.path.isdir(FILES_FOLDER):
|
||||
shutil.rmtree(FILES_FOLDER)
|
||||
|
||||
os.mkdir(FILES_FOLDER)
|
||||
|
||||
for i in range(NUM_FILES):
|
||||
temp = dict(file_test_structure)
|
||||
|
||||
temp["file"] = open(FILES_FOLDER + "/" + str(i)+ ".txt", "w+")
|
||||
temp["size"] = random.randint(1000000, 10000000)
|
||||
ALL_FILES.append(temp)
|
||||
|
||||
|
||||
for i in range(NUM_READ_WRITES):
|
||||
for j in range(NUM_FILES):
|
||||
current_file = ALL_FILES[j]
|
||||
current_file["file"].seek(0)
|
||||
current_file["file"].write(dev_random.read(current_file["size"]))
|
||||
|
||||
for j in range(NUM_FILES):
|
||||
current_file = ALL_FILES[j]
|
||||
current_file["file"].seek(0)
|
||||
current_file["file"].read(current_file["size"])
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,31 @@
|
||||
# This config is copied from overleaf so output there will match compiled output here
|
||||
|
||||
# support for the glossaries package:
|
||||
add_cus_dep('glo', 'gls', 0, 'makeglossaries');
|
||||
add_cus_dep('acn', 'acr', 0, 'makeglossaries');
|
||||
sub makeglossaries {
|
||||
system("makeglossaries \"$_[0]\"");
|
||||
}
|
||||
|
||||
# support for the nomencl package:
|
||||
add_cus_dep('nlo', 'nls', 0, 'makenlo2nls');
|
||||
sub makenlo2nls {
|
||||
system("makeindex -s nomencl.ist -o \"$_[0].nls\" \"$_[0].nlo\"");
|
||||
}
|
||||
|
||||
# from the documentation for V. 2.03 of asymptote:
|
||||
sub asy {return system("asy \"$_[0]\"");}
|
||||
add_cus_dep("asy","eps",0,"asy");
|
||||
add_cus_dep("asy","pdf",0,"asy");
|
||||
add_cus_dep("asy","tex",0,"asy");
|
||||
|
||||
# metapost rule from http://tex.stackexchange.com/questions/37134
|
||||
add_cus_dep('mp', '1', 0, 'mpost');
|
||||
sub mpost {
|
||||
my $file = $_[0];
|
||||
my ($name, $path) = fileparse($file);
|
||||
pushd($path);
|
||||
my $return = system "mpost $name";
|
||||
popd();
|
||||
return $return;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
# Makefile created by Corwin Perren
|
||||
# Generic makefile for all LaTeX projects downloaded from overleaf
|
||||
#
|
||||
# All this makefile does is call perl against latexmkrc, which is
|
||||
# the latex equivalent of make
|
||||
|
||||
LATEXMK_COMPILE_FLAGS = -cd -pdf homework2.tex
|
||||
LATEXMK_CLEAN_FLAGS = -c
|
||||
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
all: latexmk_output clean
|
||||
|
||||
latexmk_output:
|
||||
perl latexmk.pl $(LATEXMK_COMPILE_FLAGS)
|
||||
mv homework2.pdf CS444_project2_4.pdf
|
||||
|
||||
clean:
|
||||
perl latexmk.pl $(LATEXMK_CLEAN_FLAGS)
|
||||
@@ -0,0 +1,19 @@
|
||||
\section{Questions}
|
||||
\subsection{Point of Assignment}
|
||||
The point of this assignment was to explore the way that elevator algorithms are implemented as well as getting acquainted with going through all the steps needed to make and apply changes to Linux kernel modules. This required looking through the kernel elevator source files and performing research to determine how to adapt our elevator algorithm. Additionally, this assignment was an initial experience creating a patch for the Linux kernel.
|
||||
|
||||
\subsection{Problem Approach}
|
||||
We approached this problem by first reading through the Homework 2 page on Canvas and reading through the information on the noop and LOOK/CLOOK algorithms on the "I/O and provided functionality" page on Canvas. Next the "noop-iosched.c" file was copied to "sstf-iosched.c" and all references to noop were changed to sstf. Research was then performed to figure out how to get the kernel to compile, recognize, and use this scheduler. The "noop-iosched.c" file and the files it is dependent on were also explored to learn how this scheduling algorithm was implemented.
|
||||
|
||||
After this initial set-up and research, it was decided to implement the LOOK algorithm because it is the more efficient algorithm that seemed like a better choice, especially in real world use cases. In order to ensure that the queue is sorted, insertion sort is used for each of the new items added. Printk statements were placed in the queue add function to ensure that printed results of the queue's state matched what was expected from the LOOK algorithm.
|
||||
|
||||
\subsection{Correctness}
|
||||
We know that the end result was correct by using the output of the printk function calls mentioned above to log the blocks for each request as they were added and dispatched. We also added printouts of the whole queue each time an entry was added, to ensure that the entry was placed in the expected location. With these statements on the screen, verifying correctness was as simple as making sure block numbers in the queue were being added in such that if the head were on its way "up" or "down", that the data in the queue matched the current direction.
|
||||
|
||||
To ensure that the implementation worked for all reasonable accesses of the drive, a python script was written to generate many randomly sized files, as well as to randomly read this data back. By changing the number of times that the randomly generated files were read/written we were able to test the scheduler until varying scenarios of use.
|
||||
|
||||
\subsection{What Was Learned}
|
||||
We learned that documentation is extremely important to code development as it allows readers to more easily use code that has already been written. There are not many comments in the "noop-iosched.c" or the "elevator.c" file to describe how the various functions work, and this made it difficult to understand exactly how the previously written code functioned. We also learned that it can be challenging to debug while working with the kernel because sometimes the only error that you see is that the kernel does not boot, at which point using the GDB debugger is needed.
|
||||
|
||||
\subsection{How to Evaluate}
|
||||
After applying the patch file, building the kernel, and booting the VM, you should be able to see prints to the screen once the scheduler is loaded and applied to the main boot device /dev/hda. At this point, there were be a few different kinds of statements to look out for. The first will start with "[SSTF\_GROUP4] Adding ...." that will tell you when a new item is being added to the queue, what block number the access is for, and whether this is a read or write. After these add prints there will be a printout of the whole elevator queue that will immediately allow you to see where the new entry was placed in the queue. Once the system is ready for a dispatch, the kernel will also print a statement starting with "[SSTF\_GROUP4] Dispatching:..." telling you what block is being dispatched, and whether it's a read or write. By watching changes to these statements as the kernel is booting, or by using a program to generate IO, correctness of the implementation can easily be verified. We have included the python file io\_test.py in our tarball if you want to use it to generate the IO that we did for testing.
|
||||
@@ -0,0 +1,15 @@
|
||||
\section{Version Control Log}
|
||||
\begin{center}
|
||||
\begin{tabular}{l l l l} \textbf{Detail} & \textbf{Author} & \textbf{Date} &\textbf{Description}\\\hline
|
||||
|
||||
\href{.//commit/9aba09af70810709d27af320d740e677c498b79f}{9aba09a} & Corwin Perren & 2018-05-04 17:33:16 -0700 &Refactored for easier development. Added initial sstf file. Tested kernel change name. Started virtual machine as ide drive.\\\hline
|
||||
\href{.//commit/07b427a502f82dd300e79f2bce18a2f56a65fc55}{07b427a} & Corwin Perren & 2018-05-04 18:14:07 -0700 &Compiled sstf. Added untouched directory to gitignore so it doesn't have to check it each time\\\hline
|
||||
\href{.//commit/690e1a6793997bea1e327810eca7dd2838b131a3}{690e1a6} & Corwin Perren & 2018-05-04 20:31:36 -0700 &Works, but is confusing\\\hline
|
||||
\href{.//commit/9b48e6ccf10fa5b356e2ce6f1ef185c8af0c3e8b}{9b48e6c} & Corwin Perren & 2018-05-05 14:57:26 -0700 &Added new version of sstf. Removed unneeded files.\\\hline
|
||||
\href{.//commit/ce39f4775a5172d033dcd86a0ac0613af748830b}{ce39f47} & Corwin Perren & 2018-05-05 16:38:26 -0700 &Final version of homework 2\\\hline
|
||||
\href{.//commit/58376ddc3bb9791d8c277ef5612118bbe6522f55}{58376dd} & Corwin Perren & 2018-05-05 17:39:40 -0700 &Added patch file for homework2\\\hline
|
||||
|
||||
|
||||
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
@@ -0,0 +1,17 @@
|
||||
\section{Work Log}
|
||||
\begin{itemize}
|
||||
\item 2018-05-04
|
||||
\begin{itemize}
|
||||
\item Group met in Valley Library
|
||||
\item Started Latex document for Homework 2
|
||||
\item Copied noop elevator
|
||||
\item Figured out how to get the kernel to use the new elevator
|
||||
\item Started implementing the LOOK algorithm
|
||||
\end{itemize}
|
||||
\item 2018-05-05
|
||||
\begin{itemize}
|
||||
\item Group met in Valley Library
|
||||
\item Finished implementing the LOOK algorithm
|
||||
\item Created patch file
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
\section{Design}
|
||||
The framework for the device driver was taken from the "simple block device" from the website: http://blog.superpat.com/2010/05/04/a-simple-block-driver-for-linux-kernel-2-6-31/. The following changes were then needed to add crypto functionality:
|
||||
\begin{itemize}
|
||||
\item Addition of cipher
|
||||
\item Addition of cipher key
|
||||
\item Addition of module parameter for the key
|
||||
\item Change the read and write functionality so that the encryption and decryption occurs as the reads and writes happen
|
||||
\end{itemize}
|
||||
|
||||
The following psuedocode describes how the read and write functionality with encryption and decryption was implemented:
|
||||
\begin{lstlisting}[lineskip=3pt,keywords={if,else,while}]
|
||||
if (write) {
|
||||
for(iterate through desired length) {
|
||||
encrypt using crypto_cipher_encrypt_one()
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(iterate through desired length) {
|
||||
decrypt using crypto_cipher_decrypt_one()
|
||||
}
|
||||
}
|
||||
\end{lstlisting}
|
||||
@@ -0,0 +1,254 @@
|
||||
diff -Naur -x '*.o' -x '*.ko' -x '*.order' -x '*.builtin' -x '*.cmd' -x '*.mod.c' linux-yocto-3.19.2_untouched/drivers/block/encrypted_block_device.c linux-yocto-3.19.2/drivers/block/encrypted_block_device.c
|
||||
--- linux-yocto-3.19.2_untouched/drivers/block/encrypted_block_device.c 1969-12-31 16:00:00.000000000 -0800
|
||||
+++ linux-yocto-3.19.2/drivers/block/encrypted_block_device.c 2018-05-16 21:34:04.762216256 -0700
|
||||
@@ -0,0 +1,226 @@
|
||||
+/*
|
||||
+ * Encrypted block driver by Corinna Brown and Corwin Perren
|
||||
+ *
|
||||
+ * Core code pulled from the following link
|
||||
+ * http://blog.superpat.com/2010/05/04/a-simple-block-driver-for-linux-kernel-2-6-31/
|
||||
+ *
|
||||
+ * A sample, extra-simple block driver. Updated for kernel 2.6.31.
|
||||
+ *
|
||||
+ * (C) 2003 Eklektix, Inc.
|
||||
+ * (C) 2010 Pat Patterson <pat at superpat dot com>
|
||||
+ * Redistributable under the terms of the GNU GPL.
|
||||
+ */
|
||||
+
|
||||
+ #include <linux/module.h>
|
||||
+ #include <linux/moduleparam.h>
|
||||
+ #include <linux/init.h>
|
||||
+
|
||||
+ #include <linux/kernel.h> /* printk() */
|
||||
+ #include <linux/fs.h> /* everything... */
|
||||
+ #include <linux/errno.h> /* error codes */
|
||||
+ #include <linux/types.h> /* size_t */
|
||||
+ #include <linux/vmalloc.h>
|
||||
+ #include <linux/genhd.h>
|
||||
+ #include <linux/blkdev.h>
|
||||
+ #include <linux/hdreg.h>
|
||||
+ #include <linux/crypto.h>
|
||||
+
|
||||
+MODULE_LICENSE("Dual BSD/GPL");
|
||||
+static char *Version = "1.4";
|
||||
+
|
||||
+static int major_num = 0;
|
||||
+module_param(major_num, int, 0);
|
||||
+static int logical_block_size = 512;
|
||||
+module_param(logical_block_size, int, 0);
|
||||
+static int nsectors = 1024; /* How big the drive is */
|
||||
+module_param(nsectors, int, 0);
|
||||
+
|
||||
+/* Cryptography Assignment Variables */
|
||||
+
|
||||
+struct crypto_cipher *custom_cipher;
|
||||
+
|
||||
+static char *custom_cipher_key = "3a84e1ac6b54ca";
|
||||
+module_param(custom_cipher_key, charp, 0644);
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * We can tweak our hardware sector size, but the kernel talks to us
|
||||
+ * in terms of small sectors, always.
|
||||
+ */
|
||||
+#define KERNEL_SECTOR_SIZE 512
|
||||
+
|
||||
+/*
|
||||
+ * Our request queue.
|
||||
+ */
|
||||
+static struct request_queue *Queue;
|
||||
+
|
||||
+/*
|
||||
+ * The internal representation of our device.
|
||||
+ */
|
||||
+static struct sbd_device {
|
||||
+ unsigned long size;
|
||||
+ spinlock_t lock;
|
||||
+ u8 *data;
|
||||
+ struct gendisk *gd;
|
||||
+} Device;
|
||||
+
|
||||
+/*
|
||||
+ * Handle an I/O request.
|
||||
+ */
|
||||
+static void sbd_transfer(struct sbd_device *dev, sector_t sector,
|
||||
+ unsigned long nsect, char *buffer, int write) {
|
||||
+ unsigned long offset = sector * logical_block_size;
|
||||
+ unsigned long nbytes = nsect * logical_block_size;
|
||||
+
|
||||
+ unsigned char *device_buffer = dev->data + offset;
|
||||
+ unsigned char *request_buffer = buffer;
|
||||
+ int i;
|
||||
+
|
||||
+ int custom_cipher_length = sizeof(custom_cipher_key) /
|
||||
+ sizeof(custom_cipher_key[0]);
|
||||
+
|
||||
+ printk("##[GROUP4]## Custom cipher key is %s\n", custom_cipher_key);
|
||||
+ crypto_cipher_setkey(custom_cipher, custom_cipher_key, custom_cipher_length);
|
||||
+
|
||||
+ if ((offset + nbytes) > dev->size) {
|
||||
+ printk (KERN_NOTICE "sbd: Beyond-end write (%ld %ld)\n", offset, nbytes);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ printk("##[GROUP4]## Module is: %s\n", write ? "WRITING" : "READING");
|
||||
+ if (write)
|
||||
+ {
|
||||
+ for (i = 0; i < nbytes; i+= crypto_cipher_blocksize(custom_cipher)) {
|
||||
+ crypto_cipher_encrypt_one(custom_cipher, device_buffer + i,
|
||||
+ request_buffer + i);
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ for (i = 0; i < nbytes; i+= crypto_cipher_blocksize(custom_cipher)) {
|
||||
+ crypto_cipher_decrypt_one(custom_cipher, request_buffer + i,
|
||||
+ device_buffer + i);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ printk("##[GROUP4]## Encrypted Bytes ##\n");
|
||||
+ for (i = 0; i < nbytes; i++) {
|
||||
+ printk("%u", (unsigned) *device_buffer++);
|
||||
+ }
|
||||
+ printk("\n");
|
||||
+
|
||||
+ printk("##[GROUP4]## Unencrypted Bytes ##\n");
|
||||
+ for (i = 0; i < nbytes; i++) {
|
||||
+ printk("%u", (unsigned) *request_buffer++);
|
||||
+ }
|
||||
+ printk("\n\n");
|
||||
+}
|
||||
+
|
||||
+static void sbd_request(struct request_queue *q) {
|
||||
+ struct request *req;
|
||||
+
|
||||
+ req = blk_fetch_request(q);
|
||||
+ while (req != NULL) {
|
||||
+ // blk_fs_request() was removed in 2.6.36 - many thanks to
|
||||
+ // Christian Paro for the heads up and fix...
|
||||
+ //if (!blk_fs_request(req)) {
|
||||
+ if (req == NULL || (req->cmd_type != REQ_TYPE_FS)) {
|
||||
+ printk (KERN_NOTICE "Skip non-CMD request\n");
|
||||
+ __blk_end_request_all(req, -EIO);
|
||||
+ continue;
|
||||
+ }
|
||||
+ sbd_transfer(&Device, blk_rq_pos(req), blk_rq_cur_sectors(req),
|
||||
+ bio_data(req->bio), rq_data_dir(req));
|
||||
+ if ( ! __blk_end_request_cur(req, 0) ) {
|
||||
+ req = blk_fetch_request(q);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * The HDIO_GETGEO ioctl is handled in blkdev_ioctl(), which
|
||||
+ * calls this. We need to implement getgeo, since we can't
|
||||
+ * use tools such as fdisk to partition the drive otherwise.
|
||||
+ */
|
||||
+int sbd_getgeo(struct block_device * block_device, struct hd_geometry * geo) {
|
||||
+ long size;
|
||||
+
|
||||
+ /* We have no real geometry, of course, so make something up. */
|
||||
+ size = Device.size * (logical_block_size / KERNEL_SECTOR_SIZE);
|
||||
+ geo->cylinders = (size & ~0x3f) >> 6;
|
||||
+ geo->heads = 4;
|
||||
+ geo->sectors = 16;
|
||||
+ geo->start = 0;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * The device operations structure.
|
||||
+ */
|
||||
+static struct block_device_operations sbd_ops = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .getgeo = sbd_getgeo
|
||||
+};
|
||||
+
|
||||
+static int __init sbd_init(void) {
|
||||
+ /* Initialize our cipher_key */
|
||||
+ custom_cipher = crypto_alloc_cipher("aes", 0, 0);
|
||||
+
|
||||
+ /*
|
||||
+ * Set up our internal device.
|
||||
+ */
|
||||
+ Device.size = nsectors * logical_block_size;
|
||||
+ spin_lock_init(&Device.lock);
|
||||
+ Device.data = vmalloc(Device.size);
|
||||
+ if (Device.data == NULL)
|
||||
+ return -ENOMEM;
|
||||
+ /*
|
||||
+ * Get a request queue.
|
||||
+ */
|
||||
+ Queue = blk_init_queue(sbd_request, &Device.lock);
|
||||
+ if (Queue == NULL)
|
||||
+ goto out;
|
||||
+ blk_queue_logical_block_size(Queue, logical_block_size);
|
||||
+ /*
|
||||
+ * Get registered.
|
||||
+ */
|
||||
+ major_num = register_blkdev(major_num, "sbd");
|
||||
+ if (major_num < 0) {
|
||||
+ printk(KERN_WARNING "sbd: unable to get major number\n");
|
||||
+ goto out;
|
||||
+ }
|
||||
+ /*
|
||||
+ * And the gendisk structure.
|
||||
+ */
|
||||
+ Device.gd = alloc_disk(16);
|
||||
+ if (!Device.gd)
|
||||
+ goto out_unregister;
|
||||
+ Device.gd->major = major_num;
|
||||
+ Device.gd->first_minor = 0;
|
||||
+ Device.gd->fops = &sbd_ops;
|
||||
+ Device.gd->private_data = &Device;
|
||||
+ strcpy(Device.gd->disk_name, "sbd0");
|
||||
+ set_capacity(Device.gd, nsectors);
|
||||
+ Device.gd->queue = Queue;
|
||||
+ add_disk(Device.gd);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+out_unregister:
|
||||
+ unregister_blkdev(major_num, "sbd");
|
||||
+out:
|
||||
+ vfree(Device.data);
|
||||
+ return -ENOMEM;
|
||||
+}
|
||||
+
|
||||
+static void __exit sbd_exit(void)
|
||||
+{
|
||||
+ del_gendisk(Device.gd);
|
||||
+ put_disk(Device.gd);
|
||||
+ unregister_blkdev(major_num, "sbd");
|
||||
+ blk_cleanup_queue(Queue);
|
||||
+ vfree(Device.data);
|
||||
+}
|
||||
+
|
||||
+module_init(sbd_init);
|
||||
+module_exit(sbd_exit);
|
||||
diff -Naur -x '*.o' -x '*.ko' -x '*.order' -x '*.builtin' -x '*.cmd' -x '*.mod.c' linux-yocto-3.19.2_untouched/drivers/block/Kconfig linux-yocto-3.19.2/drivers/block/Kconfig
|
||||
--- linux-yocto-3.19.2_untouched/drivers/block/Kconfig 2018-05-04 15:14:54.159243368 -0700
|
||||
+++ linux-yocto-3.19.2/drivers/block/Kconfig 2018-05-16 19:58:45.301219285 -0700
|
||||
@@ -15,6 +15,9 @@
|
||||
|
||||
if BLK_DEV
|
||||
|
||||
+config BLK_DEV_EBD
|
||||
+ tristate "Homework group4 encrypted block device driver."
|
||||
+
|
||||
config BLK_DEV_NULL_BLK
|
||||
tristate "Null test block driver"
|
||||
|
||||
diff -Naur -x '*.o' -x '*.ko' -x '*.order' -x '*.builtin' -x '*.cmd' -x '*.mod.c' linux-yocto-3.19.2_untouched/drivers/block/Makefile linux-yocto-3.19.2/drivers/block/Makefile
|
||||
--- linux-yocto-3.19.2_untouched/drivers/block/Makefile 2018-05-04 15:14:54.159243368 -0700
|
||||
+++ linux-yocto-3.19.2/drivers/block/Makefile 2018-05-16 19:59:05.919571039 -0700
|
||||
@@ -30,6 +30,7 @@
|
||||
obj-$(CONFIG_BLK_DEV_NBD) += nbd.o
|
||||
obj-$(CONFIG_BLK_DEV_CRYPTOLOOP) += cryptoloop.o
|
||||
obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o
|
||||
+obj-$(CONFIG_BLK_DEV_EBD) += encrypted_block_device.o
|
||||
|
||||
obj-$(CONFIG_BLK_DEV_SX8) += sx8.o
|
||||
obj-$(CONFIG_BLK_DEV_HD) += hd.o
|
||||
@@ -0,0 +1,98 @@
|
||||
\documentclass[onecolumn, draftclsnofoot, 10pt, compsoc]{IEEEtran}
|
||||
\usepackage{graphicx}
|
||||
\graphicspath{{./figures/}}
|
||||
|
||||
\usepackage{url}
|
||||
\usepackage{setspace}
|
||||
\usepackage{multicol}
|
||||
\usepackage{pdflscape}
|
||||
\usepackage{pdfpages}
|
||||
\usepackage[british]{babel}
|
||||
\usepackage{listings}
|
||||
\usepackage{xcolor}
|
||||
\usepackage{listings}
|
||||
\usepackage{hyperref}
|
||||
\usepackage{subfig}
|
||||
|
||||
\usepackage{geometry}
|
||||
\geometry{textheight=9.5in, textwidth=7in}
|
||||
|
||||
% \overfullrule=2in
|
||||
|
||||
|
||||
%Personal \newcommands
|
||||
|
||||
\definecolor{backcolor}{rgb}{0.95,0.95,0.92}
|
||||
\lstset{basicstyle=\ttfamily,
|
||||
backgroundcolor=\color{backcolor},
|
||||
showstringspaces=false,
|
||||
commentstyle=\color{red},
|
||||
keywordstyle=\color{blue},
|
||||
columns=fullflexible,
|
||||
breaklines=true,
|
||||
postbreak=\mbox{\textcolor{red}{$\hookrightarrow$}\space},
|
||||
}
|
||||
|
||||
\newcommand{\NameSigPair}[1]{
|
||||
\par
|
||||
\makebox[2.75in][r]{#1}
|
||||
\hfill
|
||||
\makebox[3.25in]{
|
||||
\makebox[2.25in]{\hrulefill}
|
||||
\hfill
|
||||
\makebox[.75in]{\hrulefill}
|
||||
}
|
||||
\par\vspace{-12pt}
|
||||
\textit{
|
||||
\tiny\noindent
|
||||
\makebox[2.75in]{}
|
||||
\hfill
|
||||
\makebox[3.25in]{
|
||||
\makebox[2.25in][r]{Signature}
|
||||
\hfill
|
||||
\makebox[.75in][r]{Date}
|
||||
}
|
||||
}
|
||||
}
|
||||
% 3. If the document is not to be signed, uncomment the command below
|
||||
\renewcommand{\NameSigPair}[1]{#1}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\begin{document}
|
||||
\begin{titlepage}
|
||||
\pagenumbering{gobble}
|
||||
\begin{singlespace}
|
||||
\par\vspace{2in}
|
||||
\centering
|
||||
\scshape{
|
||||
\huge Operating Systems II Homework 3 \par
|
||||
{\large\today}\par
|
||||
\vspace{.5in}
|
||||
\vfill
|
||||
\vspace{5pt}
|
||||
{\large Prepared by }\par
|
||||
Group 4 \par
|
||||
% 5. comment out the line below this one if you do not wish to name your team
|
||||
\vspace{5pt}
|
||||
{\Large
|
||||
\NameSigPair{Corinna Brown}\par
|
||||
\NameSigPair{Corwin Perren}\par
|
||||
}
|
||||
\vspace{20pt}
|
||||
\begin{abstract}
|
||||
The document is our group's submission for homework three covering the design of our solution, answers to explicit assignment questions, a version control log, and a work log.
|
||||
\end{abstract}
|
||||
}
|
||||
\end{singlespace}
|
||||
\end{titlepage}
|
||||
\newpage
|
||||
\pagenumbering{arabic}
|
||||
\tableofcontents
|
||||
\clearpage
|
||||
|
||||
\input{design}
|
||||
\input{questions}
|
||||
\input{versioncontrollog}
|
||||
\input{worklog}
|
||||
|
||||
\end{document}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,31 @@
|
||||
# This config is copied from overleaf so output there will match compiled output here
|
||||
|
||||
# support for the glossaries package:
|
||||
add_cus_dep('glo', 'gls', 0, 'makeglossaries');
|
||||
add_cus_dep('acn', 'acr', 0, 'makeglossaries');
|
||||
sub makeglossaries {
|
||||
system("makeglossaries \"$_[0]\"");
|
||||
}
|
||||
|
||||
# support for the nomencl package:
|
||||
add_cus_dep('nlo', 'nls', 0, 'makenlo2nls');
|
||||
sub makenlo2nls {
|
||||
system("makeindex -s nomencl.ist -o \"$_[0].nls\" \"$_[0].nlo\"");
|
||||
}
|
||||
|
||||
# from the documentation for V. 2.03 of asymptote:
|
||||
sub asy {return system("asy \"$_[0]\"");}
|
||||
add_cus_dep("asy","eps",0,"asy");
|
||||
add_cus_dep("asy","pdf",0,"asy");
|
||||
add_cus_dep("asy","tex",0,"asy");
|
||||
|
||||
# metapost rule from http://tex.stackexchange.com/questions/37134
|
||||
add_cus_dep('mp', '1', 0, 'mpost');
|
||||
sub mpost {
|
||||
my $file = $_[0];
|
||||
my ($name, $path) = fileparse($file);
|
||||
pushd($path);
|
||||
my $return = system "mpost $name";
|
||||
popd();
|
||||
return $return;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
# Makefile created by Corwin Perren
|
||||
# Generic makefile for all LaTeX projects downloaded from overleaf
|
||||
#
|
||||
# All this makefile does is call perl against latexmkrc, which is
|
||||
# the latex equivalent of make
|
||||
|
||||
LATEXMK_COMPILE_FLAGS = -cd -pdf homework3.tex
|
||||
LATEXMK_CLEAN_FLAGS = -c
|
||||
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
all: latexmk_output clean
|
||||
|
||||
latexmk_output:
|
||||
perl latexmk.pl $(LATEXMK_COMPILE_FLAGS)
|
||||
mv homework3.pdf CS444_project3_4.pdf
|
||||
|
||||
clean:
|
||||
perl latexmk.pl $(LATEXMK_CLEAN_FLAGS)
|
||||
@@ -0,0 +1,17 @@
|
||||
\section{Questions}
|
||||
\subsection{Point of Assignment}
|
||||
The main point of this assignment was to gain experience working with device drivers and the Linux kernel crypto API. To accomplish this, a lot of research was necessary. Learning how to perform research and finding good sources for the future are also benefits of this assignment. Finally, the assignment provided experience working with module parameters.
|
||||
|
||||
\subsection{Problem Approach}
|
||||
We approached this problem by first reading through the Homework 3 page on Canvas. Then we separated the assignment into three main concepts, the device driver, crypto, and the module.
|
||||
|
||||
First we decided to implement the device driver. As suggested on the Canvas page, "SBD" was researched and an example of a sample block device was found at http://blog.superpat.com/2010/05/04/a-simple-block-driver-for-linux-kernel-2-6-31/. After some adjustments to ensure it was compatible with the version of the kernel we are using, the device driver was tested. After ensuring correct functionality of the device driver, the Linux kernel crypto API was researched. This mainly involved looking through the crypto.h file to find the functions that are available. After finding the functions we wished to use, the device driver was adapted to encrypt and decrypt data at the time that it is read or written. Finally, we added the cipher key as a module parameter. While performing the crypto development,the module was loaded as a built-in module at boot time. Once kernel parameters were added, the driver was compiled as an add-in module, scp'd to the virtual machine, installed into the kernel directories, and loaded with varying parameters as needed for testing.
|
||||
|
||||
\subsection{Correctness}
|
||||
We know that the end result was correct by first using the output of printk function calls to look at the cipher key, the current state (reading or writing), the encrypted bytes, and the unencrypted bytes. This allowed us to see what the encrypted data looked like and ensure that the encryption and decryption was being done correctly. Then we moved our block device to a module to test the module parameter. To test this, we used different cipher keys with the same input data to show that the output data changes with the different cipher keys. Lastly, we were able to verify that the driver was working correctly by directly reading data from the /dev/sdb0 device. Reading from the device directly always returned garbage encrypted data unlike when reading from the mounted directory using our driver.
|
||||
|
||||
\subsection{What Was Learned}
|
||||
We again learned that documentation is extremely important to code development as it allows readers to more easily use code that has already been written. We also learned the basics of how to use the Linux kernel crypto API as well as the basics of writing device drivers.
|
||||
|
||||
\subsection{How to Evaluate}
|
||||
After applying the patch file using patch -p1 $<$ homework3.patch from the root of the kernel directory, building the kernel, and launching the vm, you should immediately see printk statements showing the output of the driver. Once booted, a filesystem can be made per the assignment instructions and mounted to a folder using the mount command. By reading and writing data to the mounted drive and watching printk output, you will easily be able to see that the encrypted data is different than the unencrypted data. For more in depth evaluation, a boot time kernel parameter can be set with the command "encrypted\_boot\_device.custom\_cipher\_key=yourkey" to change the module parameter. Then, by following the process above with identical data input as before, you can see the printk statements for encrypted data output differing data than with the default key.
|
||||
@@ -0,0 +1,8 @@
|
||||
\section{Version Control Log}
|
||||
\begin{center}
|
||||
\begin{tabular}{l l l l} \textbf{Detail} & \textbf{Author} & \textbf{Date} &\textbf{Description}\\\hline
|
||||
|
||||
\href{.//commit/34ba569ad1c705e8d6054e20f0a129a21d2bc0c1}{34ba569} & Corwin Perren & 2018-05-16 21:45:55 -0700 &Finished homework 3\\\hline
|
||||
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
@@ -0,0 +1,14 @@
|
||||
\section{Work Log}
|
||||
\begin{itemize}
|
||||
\item 2018-05-16
|
||||
\begin{itemize}
|
||||
\item Group met in Valley Library
|
||||
\item Started Latex document for Homework 3
|
||||
\item Found an example of a sbd
|
||||
\item Updated sbd to work with correct kernel version
|
||||
\item Researched Linux kernel API and searched through crypto.h
|
||||
\item Added crypto functionality to the device driver
|
||||
\item Added module parameter
|
||||
\item Tested module
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,38 @@
|
||||
\section{Design}
|
||||
In order to implement a best-fit version of the slob, we're going to need to modify the functions slob\_alloc and slob\_page\_alloc in "slob.c". From a high level, the biggest change that needs to be made is for slob\_alloc to have an understanding of which of its pages have a block that is best sized for the allocation that is requested. This will involve not only finding a page with free blocks available, but going through all pages with free blocks available, and then choosing the page and block that is larger than, but closest to the size of the requested allocation. If along the way, we encounter a page with a block that is exactly the size we need, we can immediately choose that as the allocation point as you can't get better than perfectly sized. In the event that there are no pages with blocks available to store the requested size of allocation, the default creation of a new page will occur, providing an empty chunk of memory that will have enough space.
|
||||
|
||||
Changes to slob\_alloc:
|
||||
\begin{lstlisting}[lineskip=3pt,keywords={if,else,while,for}]
|
||||
for each page
|
||||
//section "Enough room on this page?"
|
||||
check size of all blocks on current page
|
||||
|
||||
if (no space large enough on this page) {
|
||||
continue
|
||||
}
|
||||
if (any block has a perfect fit) {
|
||||
store page
|
||||
break
|
||||
}
|
||||
else if (any block has a fit better than current best fit) {
|
||||
store page
|
||||
}
|
||||
|
||||
if (found page with block with space) {
|
||||
allocate the space
|
||||
} else {
|
||||
create a new page
|
||||
}
|
||||
|
||||
\end{lstlisting}
|
||||
|
||||
Changes to slob\_page\_alloc:
|
||||
\begin{itemize}
|
||||
\item Separate the original function so that it finds the best block (using same logic as find\_closest\_block\_size\_in\_page) and then allocates that block
|
||||
\item Take out "room enough" section because we already know there is room
|
||||
\end{itemize}
|
||||
|
||||
find\_closest\_block\_size\_in\_page:
|
||||
\begin{itemize}
|
||||
\item Uses same logic as original slob\_page\_alloc to go through each block, but searches for the best instead of the first
|
||||
\end{itemize}
|
||||
@@ -0,0 +1,18 @@
|
||||
#include <stdio.h>
|
||||
#include <linux/unistd.h>
|
||||
|
||||
#define __sys_slob_free 400
|
||||
#define __sys_slob_used 401
|
||||
|
||||
int main (void){
|
||||
float fragmentation_percent;
|
||||
long used = syscall(__sys_slob_used);
|
||||
long free = syscall(__sys_slob_free);
|
||||
|
||||
fragmentation_percent = (float) free / (float) used;
|
||||
printf("Amount free: %ld.\n", free);
|
||||
printf("Amount used: %ld.\n", used);
|
||||
printf("Amount frag: %.2f%%.\n", fragmentation_percent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,410 @@
|
||||
diff -Naur -x '*.o' -x '*.ko' -x '*.order' -x '*.builtin' -x '*.cmd' -x '*.mod.c' linux-yocto-3.19.2_untouched/mm/slob.c linux-yocto-3.19.2/mm/slob.c
|
||||
--- linux-yocto-3.19.2_untouched/mm/slob.c 2018-05-04 15:15:00.445347537 -0700
|
||||
+++ linux-yocto-3.19.2/mm/slob.c 2018-06-06 17:07:53.244403545 -0700
|
||||
@@ -68,6 +68,9 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/kmemleak.h>
|
||||
|
||||
+#include <linux/linkage.h>
|
||||
+#include <linux/syscalls.h>
|
||||
+
|
||||
#include <trace/events/kmem.h>
|
||||
|
||||
#include <linux/atomic.h>
|
||||
@@ -101,6 +104,8 @@
|
||||
static LIST_HEAD(free_slob_medium);
|
||||
static LIST_HEAD(free_slob_large);
|
||||
|
||||
+size_t num_pages = 0;
|
||||
+
|
||||
/*
|
||||
* slob_page_free: true for pages on free_slob_pages list.
|
||||
*/
|
||||
@@ -211,55 +216,117 @@
|
||||
free_pages((unsigned long)b, order);
|
||||
}
|
||||
|
||||
-/*
|
||||
- * Allocate a slob block within a given slob_page sp.
|
||||
- */
|
||||
static void *slob_page_alloc(struct page *sp, size_t size, int align)
|
||||
{
|
||||
- slob_t *prev, *cur, *aligned = NULL;
|
||||
- int delta = 0, units = SLOB_UNITS(size);
|
||||
+ slob_t *prev, *cur, *aligned = NULL, *best = NULL, *best_prev = NULL;
|
||||
+ int delta = 0;
|
||||
+ int units = SLOB_UNITS(size);
|
||||
+ slobidx_t avail;
|
||||
|
||||
+ /* Find best fit block on page that can fit what needs to be allocated */
|
||||
for (prev = NULL, cur = sp->freelist; ; prev = cur, cur = slob_next(cur)) {
|
||||
- slobidx_t avail = slob_units(cur);
|
||||
+ avail = slob_units(cur);
|
||||
|
||||
+ /* Use aligned blocks if requested */
|
||||
if (align) {
|
||||
aligned = (slob_t *)ALIGN((unsigned long)cur, align);
|
||||
delta = aligned - cur;
|
||||
}
|
||||
- if (avail >= units + delta) { /* room enough? */
|
||||
- slob_t *next;
|
||||
+
|
||||
+ /* If the current block is the best option seen yet, store it */
|
||||
+ if(avail >= units + delta && (!best || avail < slob_units(best))) {
|
||||
+ best = cur;
|
||||
+ best_prev = prev;
|
||||
+ }
|
||||
+
|
||||
+ /* If this is the last block, exit loop */
|
||||
+ if (slob_last(cur)) {
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ /* Allocate the best block found above, if found */
|
||||
+ if (best != NULL){
|
||||
+ slob_t *next;
|
||||
|
||||
- if (delta) { /* need to fragment head to align? */
|
||||
- next = slob_next(cur);
|
||||
- set_slob(aligned, avail - delta, next);
|
||||
- set_slob(cur, delta, aligned);
|
||||
- prev = cur;
|
||||
- cur = aligned;
|
||||
- avail = slob_units(cur);
|
||||
- }
|
||||
+ /* Align if necessary */
|
||||
+ if (align) {
|
||||
+ aligned = (slob_t *)ALIGN((unsigned long)best, align);
|
||||
+ delta = aligned - best;
|
||||
+ }
|
||||
+
|
||||
+ /* Get the amount of space available */
|
||||
+ avail = slob_units(best);
|
||||
|
||||
- next = slob_next(cur);
|
||||
- if (avail == units) { /* exact fit? unlink. */
|
||||
- if (prev)
|
||||
- set_slob(prev, slob_units(prev), next);
|
||||
- else
|
||||
- sp->freelist = next;
|
||||
- } else { /* fragment */
|
||||
- if (prev)
|
||||
- set_slob(prev, slob_units(prev), cur + units);
|
||||
- else
|
||||
- sp->freelist = cur + units;
|
||||
- set_slob(cur + units, avail - units, next);
|
||||
+
|
||||
+ if (delta) { /* need to fragment head to align? */
|
||||
+ next = slob_next(best);
|
||||
+ set_slob(aligned, (avail - delta), next);
|
||||
+ set_slob(best, delta, aligned);
|
||||
+ best_prev = best;
|
||||
+ best = aligned;
|
||||
+ avail = slob_units(best);
|
||||
+ }
|
||||
+
|
||||
+ next = slob_next(best);
|
||||
+
|
||||
+ /* exact fit? unlink. */
|
||||
+ if (avail == units) {
|
||||
+ if (best_prev)
|
||||
+ set_slob(best_prev, slob_units(best_prev), next);
|
||||
+ else
|
||||
+ sp->freelist = next;
|
||||
+ } else { /* fragment */
|
||||
+ if (best_prev){
|
||||
+ set_slob(best_prev, slob_units(best_prev), best + units);
|
||||
}
|
||||
+ else{
|
||||
+ sp->freelist = best + units;
|
||||
+ }
|
||||
+ set_slob(best + units, avail - units, next);
|
||||
+ }
|
||||
+
|
||||
+ sp->units -= units;
|
||||
+ if (!sp->units)
|
||||
+ clear_slob_page_free(sp);
|
||||
+ return best;
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int find_closest_block_size_in_page(struct page *sp, size_t size, int align)
|
||||
+{
|
||||
+ slob_t *prev, *cur, *aligned = NULL, *best = NULL;
|
||||
+ int delta = 0, units = SLOB_UNITS(size);
|
||||
|
||||
- sp->units -= units;
|
||||
- if (!sp->units)
|
||||
- clear_slob_page_free(sp);
|
||||
- return cur;
|
||||
+ for (prev = NULL, cur = sp->freelist; ; prev = cur, cur = slob_next(cur)) {
|
||||
+ slobidx_t avail = slob_units(cur);
|
||||
+
|
||||
+ /* Align if necessary */
|
||||
+ if (align) {
|
||||
+ aligned = (slob_t *)ALIGN((unsigned long)cur, align);
|
||||
+ delta = aligned - cur;
|
||||
}
|
||||
- if (slob_last(cur))
|
||||
- return NULL;
|
||||
+
|
||||
+ /* Keep track of the better block if we've found one */
|
||||
+ if(avail >= units + delta && (!best || avail < slob_units(best))){
|
||||
+ best = cur;
|
||||
+ }
|
||||
+
|
||||
+ /* If we're at the end, return the best block, or -1 if not found*/
|
||||
+ if (slob_last(cur)) {
|
||||
+ if(best){
|
||||
+ return slob_units(best);
|
||||
+ }else{
|
||||
+ return -1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
}
|
||||
+ return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -267,11 +334,12 @@
|
||||
*/
|
||||
static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
|
||||
{
|
||||
- struct page *sp;
|
||||
- struct list_head *prev;
|
||||
- struct list_head *slob_list;
|
||||
+ struct page *sp = NULL, *best_pg = NULL;
|
||||
+ struct list_head *slob_list = NULL;
|
||||
slob_t *b = NULL;
|
||||
unsigned long flags;
|
||||
+ slobidx_t best_fit = 0;
|
||||
+ slobidx_t cur_fit;
|
||||
|
||||
if (size < SLOB_BREAK1)
|
||||
slob_list = &free_slob_small;
|
||||
@@ -281,53 +349,67 @@
|
||||
slob_list = &free_slob_large;
|
||||
|
||||
spin_lock_irqsave(&slob_lock, flags);
|
||||
- /* Iterate through each partially free page, try to find room */
|
||||
+
|
||||
+ /* Iterate through each page for find a spot if possible */
|
||||
list_for_each_entry(sp, slob_list, lru) {
|
||||
#ifdef CONFIG_NUMA
|
||||
- /*
|
||||
- * If there's a node specification, search for a partial
|
||||
- * page with a matching node id in the freelist.
|
||||
- */
|
||||
- if (node != NUMA_NO_NODE && page_to_nid(sp) != node)
|
||||
- continue;
|
||||
+ /*
|
||||
+ * If there's a node specification, search for a partial
|
||||
+ * page with a matching node id in the freelist.
|
||||
+ */
|
||||
+ if (node != NUMA_NO_NODE && page_to_nid(sp) != node)
|
||||
+ continue;
|
||||
#endif
|
||||
- /* Enough room on this page? */
|
||||
- if (sp->units < SLOB_UNITS(size))
|
||||
- continue;
|
||||
-
|
||||
- /* Attempt to alloc */
|
||||
- prev = sp->lru.prev;
|
||||
- b = slob_page_alloc(sp, size, align);
|
||||
- if (!b)
|
||||
- continue;
|
||||
-
|
||||
- /* Improve fragment distribution and reduce our average
|
||||
- * search time by starting our next search here. (see
|
||||
- * Knuth vol 1, sec 2.5, pg 449) */
|
||||
- if (prev != slob_list->prev &&
|
||||
- slob_list->next != prev->next)
|
||||
- list_move_tail(slob_list, prev->next);
|
||||
- break;
|
||||
+ /* Enough room on this page? */
|
||||
+ if (sp->units < SLOB_UNITS(size))
|
||||
+ continue;
|
||||
+
|
||||
+ /* Find out if there's space for this in the current page */
|
||||
+ cur_fit = find_closest_block_size_in_page(sp, size, align);
|
||||
+
|
||||
+ /* If not, continue*/
|
||||
+ if(cur_fit == -1){
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* Stop if we've found something that perfectly matches */
|
||||
+ if (cur_fit == SLOB_UNITS(size)) {
|
||||
+ best_pg = sp;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ /* Store the current best fit block, if it's better than previous */
|
||||
+ if (best_fit > cur_fit || best_pg == NULL) {
|
||||
+ best_pg = sp;
|
||||
+ best_fit = cur_fit;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Attempt to allocate */
|
||||
+ if(best_pg != NULL){
|
||||
+ b = slob_page_alloc(best_pg, size, align);
|
||||
}
|
||||
+
|
||||
spin_unlock_irqrestore(&slob_lock, flags);
|
||||
|
||||
- /* Not enough space: must allocate a new page */
|
||||
+ /* Make a new page if we never found a spot */
|
||||
if (!b) {
|
||||
- b = slob_new_pages(gfp & ~__GFP_ZERO, 0, node);
|
||||
- if (!b)
|
||||
- return NULL;
|
||||
- sp = virt_to_page(b);
|
||||
- __SetPageSlab(sp);
|
||||
-
|
||||
- spin_lock_irqsave(&slob_lock, flags);
|
||||
- sp->units = SLOB_UNITS(PAGE_SIZE);
|
||||
- sp->freelist = b;
|
||||
- INIT_LIST_HEAD(&sp->lru);
|
||||
- set_slob(b, SLOB_UNITS(PAGE_SIZE), b + SLOB_UNITS(PAGE_SIZE));
|
||||
- set_slob_page_free(sp, slob_list);
|
||||
- b = slob_page_alloc(sp, size, align);
|
||||
- BUG_ON(!b);
|
||||
- spin_unlock_irqrestore(&slob_lock, flags);
|
||||
+ b = slob_new_pages(gfp & ~__GFP_ZERO, 0, node);
|
||||
+ if (!b)
|
||||
+ return NULL;
|
||||
+ sp = virt_to_page(b);
|
||||
+ __SetPageSlab(sp);
|
||||
+
|
||||
+ spin_lock_irqsave(&slob_lock, flags);
|
||||
+ sp->units = SLOB_UNITS(PAGE_SIZE);
|
||||
+ sp->freelist = b;
|
||||
+ INIT_LIST_HEAD(&sp->lru);
|
||||
+ set_slob(b, SLOB_UNITS(PAGE_SIZE), b + SLOB_UNITS(PAGE_SIZE));
|
||||
+ set_slob_page_free(sp, slob_list);
|
||||
+ b = slob_page_alloc(sp, size, align);
|
||||
+ BUG_ON(!b);
|
||||
+ spin_unlock_irqrestore(&slob_lock, flags);
|
||||
+ num_pages++;
|
||||
}
|
||||
if (unlikely((gfp & __GFP_ZERO) && b))
|
||||
memset(b, 0, size);
|
||||
@@ -362,6 +444,7 @@
|
||||
__ClearPageSlab(sp);
|
||||
page_mapcount_reset(sp);
|
||||
slob_free_pages(b, 0);
|
||||
+ num_pages--;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -640,3 +723,31 @@
|
||||
{
|
||||
slab_state = FULL;
|
||||
}
|
||||
+
|
||||
+asmlinkage long sys_slob_free(void) {
|
||||
+ struct list_head *temp;
|
||||
+ struct page *sp;
|
||||
+ unsigned long free_units = 0;
|
||||
+
|
||||
+ temp = &free_slob_small;
|
||||
+ list_for_each_entry(sp, temp, lru) {
|
||||
+ free_units += sp->units;
|
||||
+ }
|
||||
+ temp = &free_slob_medium;
|
||||
+ list_for_each_entry(sp, temp, lru) {
|
||||
+ free_units += sp->units;
|
||||
+ }
|
||||
+ temp = &free_slob_large;
|
||||
+ list_for_each_entry(sp, temp, lru) {
|
||||
+ free_units += sp->units;
|
||||
+ }
|
||||
+
|
||||
+ return free_units;
|
||||
+}
|
||||
+
|
||||
+asmlinkage long sys_slob_used(void) {
|
||||
+ long slob_total_used;
|
||||
+
|
||||
+ slob_total_used = SLOB_UNITS(PAGE_SIZE) * num_pages;
|
||||
+ return slob_total_used;
|
||||
+}
|
||||
\ No newline at end of file
|
||||
diff -Naur -x '*.o' -x '*.ko' -x '*.order' -x '*.builtin' -x '*.cmd' -x '*.mod.c' linux-yocto-3.19.2_untouched/include/linux/syscalls.h linux-yocto-3.19.2/include/linux/syscalls.h
|
||||
--- linux-yocto-3.19.2_untouched/include/linux/syscalls.h 2018-05-04 15:14:59.075324834 -0700
|
||||
+++ linux-yocto-3.19.2/include/linux/syscalls.h 2018-06-06 16:32:02.518020727 -0700
|
||||
@@ -882,4 +882,6 @@
|
||||
const char __user *const __user *argv,
|
||||
const char __user *const __user *envp, int flags);
|
||||
|
||||
+asmlinkage long sys_slob_free(void);
|
||||
+asmlinkage long sys_slob_used(void);
|
||||
#endif
|
||||
diff -Naur -x '*.o' -x '*.ko' -x '*.order' -x '*.builtin' -x '*.cmd' -x '*.mod.c' linux-yocto-3.19.2_untouched/arch/x86/syscalls/syscall_32.tbl linux-yocto-3.19.2/arch/x86/syscalls/syscall_32.tbl
|
||||
--- linux-yocto-3.19.2_untouched/arch/x86/syscalls/syscall_32.tbl 2018-05-04 15:14:40.077010007 -0700
|
||||
+++ linux-yocto-3.19.2/arch/x86/syscalls/syscall_32.tbl 2018-06-06 16:31:26.578421117 -0700
|
||||
@@ -365,3 +365,6 @@
|
||||
356 i386 memfd_create sys_memfd_create
|
||||
357 i386 bpf sys_bpf
|
||||
358 i386 execveat sys_execveat stub32_execveat
|
||||
+
|
||||
+400 i386 slob_free sys_slob_free
|
||||
+401 i386 slob_used sys_slob_used
|
||||
\ No newline at end of file
|
||||
--- linux-yocto-3.19.2_untouched/.config 2018-05-04 15:15:03.830403632 -0700
|
||||
+++ linux-yocto-3.19.2/.config 2018-06-05 17:11:02.799939154 -0700
|
||||
@@ -146,7 +146,6 @@
|
||||
CONFIG_MEMCG=y
|
||||
CONFIG_MEMCG_SWAP=y
|
||||
CONFIG_MEMCG_SWAP_ENABLED=y
|
||||
-CONFIG_MEMCG_KMEM=y
|
||||
# CONFIG_CGROUP_PERF is not set
|
||||
CONFIG_CGROUP_SCHED=y
|
||||
CONFIG_FAIR_GROUP_SCHED=y
|
||||
@@ -211,12 +210,10 @@
|
||||
CONFIG_PERF_EVENTS=y
|
||||
# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
|
||||
CONFIG_VM_EVENT_COUNTERS=y
|
||||
-CONFIG_SLUB_DEBUG=y
|
||||
CONFIG_COMPAT_BRK=y
|
||||
# CONFIG_SLAB is not set
|
||||
-CONFIG_SLUB=y
|
||||
-# CONFIG_SLOB is not set
|
||||
-CONFIG_SLUB_CPU_PARTIAL=y
|
||||
+# CONFIG_SLUB is not set
|
||||
+CONFIG_SLOB=y
|
||||
# CONFIG_SYSTEM_TRUSTED_KEYRING is not set
|
||||
CONFIG_PROFILING=y
|
||||
CONFIG_TRACEPOINTS=y
|
||||
@@ -251,7 +248,6 @@
|
||||
CONFIG_HAVE_PERF_USER_STACK_DUMP=y
|
||||
CONFIG_HAVE_ARCH_JUMP_LABEL=y
|
||||
CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
|
||||
-CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
|
||||
CONFIG_HAVE_CMPXCHG_LOCAL=y
|
||||
CONFIG_HAVE_CMPXCHG_DOUBLE=y
|
||||
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
|
||||
@@ -275,7 +271,6 @@
|
||||
# CONFIG_GCOV_KERNEL is not set
|
||||
CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
|
||||
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
|
||||
-CONFIG_SLABINFO=y
|
||||
CONFIG_RT_MUTEXES=y
|
||||
CONFIG_BASE_SMALL=0
|
||||
CONFIG_MODULES=y
|
||||
@@ -3787,8 +3782,6 @@
|
||||
# CONFIG_PAGE_EXTENSION is not set
|
||||
# CONFIG_DEBUG_PAGEALLOC is not set
|
||||
# CONFIG_DEBUG_OBJECTS is not set
|
||||
-# CONFIG_SLUB_DEBUG_ON is not set
|
||||
-# CONFIG_SLUB_STATS is not set
|
||||
CONFIG_HAVE_DEBUG_KMEMLEAK=y
|
||||
# CONFIG_DEBUG_KMEMLEAK is not set
|
||||
# CONFIG_DEBUG_STACK_USAGE is not set
|
||||
@@ -0,0 +1,99 @@
|
||||
\documentclass[onecolumn, draftclsnofoot, 10pt, compsoc]{IEEEtran}
|
||||
\usepackage{graphicx}
|
||||
\graphicspath{{./figures/}}
|
||||
|
||||
\usepackage{url}
|
||||
\usepackage{setspace}
|
||||
\usepackage{multicol}
|
||||
\usepackage{pdflscape}
|
||||
\usepackage{pdfpages}
|
||||
\usepackage[british]{babel}
|
||||
\usepackage{listings}
|
||||
\usepackage{xcolor}
|
||||
\usepackage{listings}
|
||||
\usepackage{hyperref}
|
||||
\usepackage{subfig}
|
||||
\usepackage{textcomp}
|
||||
|
||||
\usepackage{geometry}
|
||||
\geometry{textheight=9.5in, textwidth=7in}
|
||||
|
||||
% \overfullrule=2in
|
||||
|
||||
|
||||
%Personal \newcommands
|
||||
|
||||
\definecolor{backcolor}{rgb}{0.95,0.95,0.92}
|
||||
\lstset{basicstyle=\ttfamily,
|
||||
backgroundcolor=\color{backcolor},
|
||||
showstringspaces=false,
|
||||
commentstyle=\color{red},
|
||||
keywordstyle=\color{blue},
|
||||
columns=fullflexible,
|
||||
breaklines=true,
|
||||
postbreak=\mbox{\textcolor{red}{$\hookrightarrow$}\space},
|
||||
}
|
||||
|
||||
\newcommand{\NameSigPair}[1]{
|
||||
\par
|
||||
\makebox[2.75in][r]{#1}
|
||||
\hfill
|
||||
\makebox[3.25in]{
|
||||
\makebox[2.25in]{\hrulefill}
|
||||
\hfill
|
||||
\makebox[.75in]{\hrulefill}
|
||||
}
|
||||
\par\vspace{-12pt}
|
||||
\textit{
|
||||
\tiny\noindent
|
||||
\makebox[2.75in]{}
|
||||
\hfill
|
||||
\makebox[3.25in]{
|
||||
\makebox[2.25in][r]{Signature}
|
||||
\hfill
|
||||
\makebox[.75in][r]{Date}
|
||||
}
|
||||
}
|
||||
}
|
||||
% 3. If the document is not to be signed, uncomment the command below
|
||||
\renewcommand{\NameSigPair}[1]{#1}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\begin{document}
|
||||
\begin{titlepage}
|
||||
\pagenumbering{gobble}
|
||||
\begin{singlespace}
|
||||
\par\vspace{2in}
|
||||
\centering
|
||||
\scshape{
|
||||
\huge Operating Systems II Homework 4 \par
|
||||
{\large\today}\par
|
||||
\vspace{.5in}
|
||||
\vfill
|
||||
\vspace{5pt}
|
||||
{\large Prepared by }\par
|
||||
Group 4 \par
|
||||
% 5. comment out the line below this one if you do not wish to name your team
|
||||
\vspace{5pt}
|
||||
{\Large
|
||||
\NameSigPair{Corinna Brown}\par
|
||||
\NameSigPair{Corwin Perren}\par
|
||||
}
|
||||
\vspace{20pt}
|
||||
\begin{abstract}
|
||||
The document is our group's submission for homework four covering the design of our solution, answers to explicit assignment questions, a version control log, and a work log.
|
||||
\end{abstract}
|
||||
}
|
||||
\end{singlespace}
|
||||
\end{titlepage}
|
||||
\newpage
|
||||
\pagenumbering{arabic}
|
||||
\tableofcontents
|
||||
\clearpage
|
||||
|
||||
\input{design}
|
||||
\input{questions}
|
||||
\input{versioncontrollog}
|
||||
\input{worklog}
|
||||
|
||||
\end{document}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,31 @@
|
||||
# This config is copied from overleaf so output there will match compiled output here
|
||||
|
||||
# support for the glossaries package:
|
||||
add_cus_dep('glo', 'gls', 0, 'makeglossaries');
|
||||
add_cus_dep('acn', 'acr', 0, 'makeglossaries');
|
||||
sub makeglossaries {
|
||||
system("makeglossaries \"$_[0]\"");
|
||||
}
|
||||
|
||||
# support for the nomencl package:
|
||||
add_cus_dep('nlo', 'nls', 0, 'makenlo2nls');
|
||||
sub makenlo2nls {
|
||||
system("makeindex -s nomencl.ist -o \"$_[0].nls\" \"$_[0].nlo\"");
|
||||
}
|
||||
|
||||
# from the documentation for V. 2.03 of asymptote:
|
||||
sub asy {return system("asy \"$_[0]\"");}
|
||||
add_cus_dep("asy","eps",0,"asy");
|
||||
add_cus_dep("asy","pdf",0,"asy");
|
||||
add_cus_dep("asy","tex",0,"asy");
|
||||
|
||||
# metapost rule from http://tex.stackexchange.com/questions/37134
|
||||
add_cus_dep('mp', '1', 0, 'mpost');
|
||||
sub mpost {
|
||||
my $file = $_[0];
|
||||
my ($name, $path) = fileparse($file);
|
||||
pushd($path);
|
||||
my $return = system "mpost $name";
|
||||
popd();
|
||||
return $return;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
# Makefile created by Corwin Perren
|
||||
# Generic makefile for all LaTeX projects downloaded from overleaf
|
||||
#
|
||||
# All this makefile does is call perl against latexmkrc, which is
|
||||
# the latex equivalent of make
|
||||
|
||||
LATEXMK_COMPILE_FLAGS = -cd -pdf homework4.tex
|
||||
LATEXMK_CLEAN_FLAGS = -c
|
||||
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
all: latexmk_output clean
|
||||
|
||||
latexmk_output:
|
||||
perl latexmk.pl $(LATEXMK_COMPILE_FLAGS)
|
||||
mv homework4.pdf CS444_project4_4.pdf
|
||||
|
||||
clean:
|
||||
perl latexmk.pl $(LATEXMK_CLEAN_FLAGS)
|
||||
@@ -0,0 +1,44 @@
|
||||
\section{Questions}
|
||||
\subsection{Point of Assignment}
|
||||
One of the main points of this assignment was to gain experience working with the memory management system in Linux. Working with slob.c requires knowledge of how memory is organized and how to access this memory. Doing this also provides more experience modifying existing kernel code. Finally this assignment also provided an opportunity to create and use a custom system call.
|
||||
|
||||
\subsection{Problem Approach}
|
||||
We approached this problem by first reading the HW4 page on Canvas and reading through the slob.c file in the "mm" folder. After reaching an understanding of how the "slob.c" file works, we set up our kernel to use SLOB instead of SLAB.
|
||||
|
||||
Next we started to create a design for how we would implement the best-fit algorithm. This involved determining which functions were being used to implement first-fit. These functions were found to be "slob\_alloc" and "slob\_page\_alloc". To implement best-fit we modified these and added a helper function "find\_closest\_block\_size\_in\_page". After this was tested and correctly functioning, we added two system call functions that find the amount of free memory and the amount of used memory by finding the number of pages being used and the amount of space on each page that is free. These system calls were also added to a unmodified version of the kernel's slob.c to test the fragmentation of the first-fit algorithm in comparison to the best-fit algorithm. These system calls were added to the system call table, and a program was written to call these system calls in order to test both algorithms. Each algorithm was then tested five times. The results of these tests are in the "Correctness" section below.
|
||||
|
||||
\subsection{Correctness}
|
||||
The test results are shown in Table 1 below. The test was run five different times on each of the two kernels with the different algorithms. To calculate the fragmentation, the following equation was used:
|
||||
\[ \frac{free blocks}{total blocks}*100 = fragmentation \]
|
||||
The average fragmentation over these five tests was then calculated. The average fragmentation was found to be 5.80\% for first-fit and 4.20\% for best-fit.
|
||||
|
||||
\begin{table}[ht]
|
||||
\caption{Fragmentation of First-Fit vs. Best-Fit Algorithms} % title of Table
|
||||
\centering % used for centering table
|
||||
\begin{tabular}{ c | c c c | c c c } % centered columns (7 columns)
|
||||
\hline\hline %inserts double horizontal lines
|
||||
& \multicolumn{3}{| c |}{First-Fit} & \multicolumn{3}{ c }{Best-Fit}\\
|
||||
\hline
|
||||
Trial & Free Blocks & Total Blocks & Fragmentation & Free Blocks & Total Blocks & Fragmentation \\ [0.5ex] % inserts table
|
||||
%heading
|
||||
\hline % inserts single horizontal line
|
||||
1 & 303776 & 5220352 & 5.82\% & 217544 & 5132288 & 4.24\% \\ % inserting body of the table
|
||||
2 & 303032 & 5220352 & 5.80\% & 214686 & 5130240 & 4.18\% \\
|
||||
3 & 304898 & 5220400 & 5.84\% & 215515 & 5130240 & 4.20\% \\
|
||||
4 & 303096 & 5220352 & 5.81\% & 213248 & 5128192 & 4.16\% \\
|
||||
5 & 298986 & 5216256 & 5.73\% & 215862 & 5130240 & 4.21\% \\
|
||||
\hline
|
||||
Average & & & 5.80\% & & & 4.20\% \\
|
||||
\hline %inserts single line
|
||||
\end{tabular}
|
||||
\label{table:nonlin} % is used to refer this table in the text
|
||||
\end{table}
|
||||
|
||||
As can be seen from the table, the fragmentation values fo r the best-fit algorithm are lower than those for the default first-fit one that ships with the kernel. This proves out implementation is correct as the best-fit model, while slower, does use the allocated pages in memory more efficiently than first-fit.
|
||||
|
||||
|
||||
\subsection{What Was Learned}
|
||||
We learned in this lab that the memory management system in linux is large and complex. We also learned that best-fit has less fragmentation than first-fit. However, there is a trade-off as best-fit also causes the kernel to boot significantly slower than with first-fit. Finally we learned how to create a custom system call, how to add it to the system call table, and how to use it.
|
||||
|
||||
\subsection{How to Evaluate}
|
||||
To evaluate this, get a clean version of the linux yocto kernel and copy the patch file into the root of the directory. Run "patch -p1 -t $<$ homework4.patch" to apply the changes to the necessary files. Make the kernel using "make -j4". Boot the kernel and scp the "find\_fragmentation.c" file into the running vm. Run "gcc find\_fragmentation.c -o frag\_check" on the vm's command line to build the fragmentation source into a binary. Run the binary with "./frag\_check". If the program outputs reasonable values for free, used, and fragmentation the kernel was built and is running correctly using the modified slob algorithm. The values on a cleanly booted system should closely match the best-fit table values from above.
|
||||
@@ -0,0 +1,11 @@
|
||||
\section{Version Control Log}
|
||||
\begin{center}
|
||||
\begin{tabular}{l l l l} \textbf{Detail} & \textbf{Author} & \textbf{Date} &\textbf{Description}\\\hline
|
||||
|
||||
\href{.//commit/3b486d3c5ba08b193bc64b47e5cab98ac4cbbafe}{3b486d3} & Corwin Perren & 2018-06-05 18:16:42 -0700 &Clean kernels for homework 4. *Design commited here*\\\hline
|
||||
\href{.//commit/5b7861a5682daf082272f8e0dd24a0174ef70f4b}{5b7861a} & Corwin Perren & 2018-06-05 18:26:26 -0700 &Missed adding updated files from previous commit.\\\hline
|
||||
\href{.//commit/608c1fc75c1be5e2a87a81185c3a09712ca5232f}{608c1fc} & Corwin Perren & 2018-06-06 18:00:36 -0700 &Finished hw4. Patch made. Tested.\\\hline
|
||||
|
||||
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
@@ -0,0 +1,20 @@
|
||||
\section{Work Log}
|
||||
\begin{itemize}
|
||||
\item 06-05-2019
|
||||
\begin{itemize}
|
||||
\item Group met in Valley Library
|
||||
\item Started Latex document for Homework 4
|
||||
\item Read through slob.c
|
||||
\item Created initial design for best-fit algorithm
|
||||
\item Began work modifying slob.c
|
||||
\end{itemize}
|
||||
\item 06-06-2019
|
||||
\begin{itemize}
|
||||
\item Group met in Valley Library
|
||||
\item Made working version of best-fit slob.c
|
||||
\item Ran performance tests between algorithms
|
||||
\item Created patch file
|
||||
\item Finished latex document
|
||||
\item Turned in assignment
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,31 @@
|
||||
# This config is copied from overleaf so output there will match compiled output here
|
||||
|
||||
# support for the glossaries package:
|
||||
add_cus_dep('glo', 'gls', 0, 'makeglossaries');
|
||||
add_cus_dep('acn', 'acr', 0, 'makeglossaries');
|
||||
sub makeglossaries {
|
||||
system("makeglossaries \"$_[0]\"");
|
||||
}
|
||||
|
||||
# support for the nomencl package:
|
||||
add_cus_dep('nlo', 'nls', 0, 'makenlo2nls');
|
||||
sub makenlo2nls {
|
||||
system("makeindex -s nomencl.ist -o \"$_[0].nls\" \"$_[0].nlo\"");
|
||||
}
|
||||
|
||||
# from the documentation for V. 2.03 of asymptote:
|
||||
sub asy {return system("asy \"$_[0]\"");}
|
||||
add_cus_dep("asy","eps",0,"asy");
|
||||
add_cus_dep("asy","pdf",0,"asy");
|
||||
add_cus_dep("asy","tex",0,"asy");
|
||||
|
||||
# metapost rule from http://tex.stackexchange.com/questions/37134
|
||||
add_cus_dep('mp', '1', 0, 'mpost');
|
||||
sub mpost {
|
||||
my $file = $_[0];
|
||||
my ($name, $path) = fileparse($file);
|
||||
pushd($path);
|
||||
my $return = system "mpost $name";
|
||||
popd();
|
||||
return $return;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
# Makefile created by Corwin Perren
|
||||
# Generic makefile for all LaTeX projects downloaded from overleaf
|
||||
#
|
||||
# All this makefile does is call perl against latexmkrc, which is
|
||||
# the latex equivalent of make
|
||||
|
||||
LATEXMK_COMPILE_FLAGS = -cd -pdf output.tex
|
||||
LATEXMK_CLEAN_FLAGS = -c
|
||||
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
all: latexmk_output clean
|
||||
|
||||
latexmk_output:
|
||||
perl latexmk.pl $(LATEXMK_COMPILE_FLAGS)
|
||||
mv output.pdf CS444_writing1_perrenc.pdf
|
||||
|
||||
clean:
|
||||
perl latexmk.pl $(LATEXMK_CLEAN_FLAGS)
|
||||
@@ -0,0 +1,92 @@
|
||||
\documentclass[onecolumn, draftclsnofoot, 10pt, compsoc]{IEEEtran}
|
||||
\usepackage{graphicx}
|
||||
\graphicspath{{./figures/}}
|
||||
|
||||
\usepackage{url}
|
||||
\usepackage{setspace}
|
||||
\usepackage{multicol}
|
||||
\usepackage{pdflscape}
|
||||
\usepackage{pdfpages}
|
||||
\usepackage[british]{babel}
|
||||
\usepackage{listings}
|
||||
\usepackage{xcolor}
|
||||
\usepackage{listings}
|
||||
\usepackage{hyperref}
|
||||
\usepackage{subfig}
|
||||
|
||||
\usepackage{geometry}
|
||||
\geometry{textheight=9.5in, textwidth=7in}
|
||||
|
||||
% \overfullrule=2in
|
||||
|
||||
|
||||
%Personal \newcommands
|
||||
|
||||
\definecolor{backcolor}{rgb}{0.95,0.95,0.92}
|
||||
\lstset{basicstyle=\ttfamily,
|
||||
backgroundcolor=\color{backcolor},
|
||||
showstringspaces=false,
|
||||
commentstyle=\color{red},
|
||||
keywordstyle=\color{blue},
|
||||
columns=fullflexible,
|
||||
breaklines=true,
|
||||
postbreak=\mbox{\textcolor{red}{$\hookrightarrow$}\space},
|
||||
}
|
||||
|
||||
\newcommand{\NameSigPair}[1]{
|
||||
\par
|
||||
\makebox[2.75in][r]{#1}
|
||||
\hfill
|
||||
\makebox[3.25in]{
|
||||
\makebox[2.25in]{\hrulefill}
|
||||
\hfill
|
||||
\makebox[.75in]{\hrulefill}
|
||||
}
|
||||
\par\vspace{-12pt}
|
||||
\textit{
|
||||
\tiny\noindent
|
||||
\makebox[2.75in]{}
|
||||
\hfill
|
||||
\makebox[3.25in]{
|
||||
\makebox[2.25in][r]{Signature}
|
||||
\hfill
|
||||
\makebox[.75in][r]{Date}
|
||||
}
|
||||
}
|
||||
}
|
||||
% 3. If the document is not to be signed, uncomment the command below
|
||||
\renewcommand{\NameSigPair}[1]{#1}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\begin{document}
|
||||
\begin{titlepage}
|
||||
\pagenumbering{gobble}
|
||||
\begin{singlespace}
|
||||
\par\vspace{2in}
|
||||
\centering
|
||||
\scshape{
|
||||
\huge Operating Systems II Writing 1 \par
|
||||
{\large\today}\par
|
||||
\vspace{.5in}
|
||||
\vfill
|
||||
\vspace{5pt}
|
||||
{\large Prepared by }\par
|
||||
|
||||
{\Large
|
||||
\NameSigPair{Corwin Perren}\par
|
||||
}
|
||||
\vspace{20pt}
|
||||
}
|
||||
\end{singlespace}
|
||||
\end{titlepage}
|
||||
\newpage
|
||||
\pagenumbering{arabic}
|
||||
|
||||
\input{writing}
|
||||
|
||||
\end{document}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
\section{Individual OS Info}
|
||||
\subsection{Windows}
|
||||
\subsubsection{Processes}
|
||||
Processes in Windows are items with a unique process ID and at least one thread. They contain information about open handles to file system objects, virtual addresses for memory, and access token to ensure that the process is being run using the correct user. In Windows, child processes know very little about their parent process, literally just their parent's PID. If the parent dies, the child processes will continue running until they are terminated another way.
|
||||
\subsubsection{Threads}
|
||||
In Windows, there are multiple kinds of threads available. These are single, apartment, free, and a combination of both apartment and free. Single threaded threads run on the main process and cause code to block as other parts run. Apartment threading gives each thread its own "apartment" inside of the the larger process "building". This allows each thread to run independently and to share resources. Free threads are run as a multi-threaded apartment object and will incur a large communications penalty if threads needed to intercommunicate as the threads do not have direction access to each other. The final options which is a combination of both of the last two allows for direct access while multi-threading but without the performance issues of either.
|
||||
\subsubsection{Scheduling}
|
||||
The Windows scheduled uses a multilevel queue to handle its processes. Processes are assigned a priority value from 0-31 with higher numbers being higher priority. When the scheduler tries to determine which thread to give time on the CPU, it first starts by checking the threads with the highest priority and giving any that are ready their time up to a maximum that's set at a system level. Once that priority level has no more processes that are ready, it goes to the next lower priority value. However, if a higher priority process becomes ready while that lower priority process is running, the lower priority process will be slept so the more important one can run.
|
||||
|
||||
\subsection{FreeBSD}
|
||||
\subsubsection{Processes}
|
||||
Processes in FreeBSD have a process ID, group, owner, and permissions that determine what the process can interact with. The process also knows what its parent ID is. If the process does not take any direct user input on a command line or GUI, the process is known as a daemon. When child processes are made, these child processes will die if the parent process dies.
|
||||
\subsubsection{Threads}
|
||||
FreeBSD actually implements two different implementations of threading. The first is M:N threading (hybrid threading) where the threads get placed onto their own kernel entities. This complicates the underlying kernel code for handling threads but allows for fast context switching as the threading library itself schedules the threads on the CPU. However, this also means that if the library isn't well or efficiently coordinated, thread efficiency can suffer. Because it is a complex threading method, it also makes code harder to maintain.
|
||||
The other threading library uses the 1:1 threading model where each thread has its own kernel threads. This model has the benefit of being able to split across multiple CPU cores, but can be slow to setup the threads themselves. The kernel also has a low limit on the number of threads that can be created in total, creating a bottleneck for systems such as servers that need to spawn many many processes with many threads.
|
||||
\subsubsection{Scheduling}
|
||||
|
||||
The FreeBSD scheduler is called the ULE scheduler after the word schedULEr itself. This is a more recent scheduler in the total lifespan of FreeBSD but is now default on all the mainline distros. The scheduler is a queue based and cuts up the CPU into time slices that it shares among the queue using load balancing algorithms. Overall, it tries to be fair about how it schedules time on the CPU, but unlike older scheduling systems for the OS, it does have some prioritization built in so that important processes such as those that the user is currently interacting with can be given a little extra CPU time.
|
||||
|
||||
\subsection{Linux}
|
||||
\subsubsection{Processes}
|
||||
So far as I can tell, the core information that processes store is the same on linux as it is on FreeBSD. This includes the process ID, group, owner, and runtime permissions. Same as FreeBSD, child processes of a parent will die if the parent dies.
|
||||
\subsubsection{Threads}
|
||||
Threads on linux are implemented using pthread. Essentially, pthread creates a clone of the process is it called from, allowing it to share the same memory space, but running a different section of code. This implementation is a 1:1 model where a new process is created for each thread, but can be changed depending on the exact version of linux being used to be part of the same parent thread instead.
|
||||
\subsubsection{Scheduling}
|
||||
The scheduler on linux is called the completely fair scheduler, or CFS for short. Unlike other operating systems, the CFS does not use traditional queues but instead uses a red/black tree where the indexes are the amount of time the process has spent on the CPU. Because of this implementation, the code for this scheduler is much more complex than other systems such as a queue. However, what this tree does allow for is very easy picking of which process needs to run next. Items on the left side of the tree are the ones that haven't had as much processor time, where the ones on the right have had enough time that they should continue waiting.
|
||||
|
||||
|
||||
\section{Inter-OS Comparisons}
|
||||
\subsection{Windows vs. Linux}
|
||||
Windows and Linux are surprisingly different in terms of how each system handles their processes, threads, and scheduling. At their root, there are definitely similar features such as process IDs, child processes, and runtime permissions but ultimately they're implemented in very different ways. The biggest two differences are in how threading is handled and the way their schedulers work. Windows has more in common with FreeBSD in this context, where the threads can be adapted to whichever mode is most useful and efficient to the user at any given time, and is a stark contrast to linux's 1:1 mode. The schedulers couldn't really be more different. Linux focuses on maintaining fair CPU usage time on the processor where Windows is all about making sure processes that are deemed more important get more time, quite explicitly. Ultimately, I can understand why both OSes would choose to take the routes they did. For Windows, they wanted to make sure lower level important system processes could never be overrun by less important user processes. And in Linux, this essentially was handled by making sure that both user and system processes couldn't take up too much time because they'd always have to share. It's really two different valid solutions to the same problem.
|
||||
|
||||
\subsection{FreeBSD vs. Linux}
|
||||
Ultimately, FreeBSD and Linux are both derived from a common background of Unix and it shows in that they're both quite similar. Process-wise, the two operating systems are nearly identical, and while they're not identical when it comes to threading, they both have overlap in that they either run or can run in 1:1 threading models where a unique kernel thread is made for each. The biggest difference between the two operating systems seems to be that the schedulers are extremely different. While FreeBSD uses a queue based system, linux's red/black fair scheduler is a much more complex scheduler. Ultimately, to me it looks like FreeBSD is more focused around maintaining backwards compatibility while providing the most flexibility and options to the user. Linux on the other hand very much seems to be more pointed towards working out over time what the BEST solution to each problem is, whether it be threading or scheduling, and making it the primary way the OS functions in the expectation that by designing the OS right the first time, the user won't have to worry about it as much.
|
||||
|
||||
\subsection{FreeBSD/Linux Code Comparison}
|
||||
\subsubsection{FreeBSD}
|
||||
\begin{lstlisting}[language=c++]
|
||||
static struct thread *
|
||||
tdq_choose(struct tdq *tdq)
|
||||
{
|
||||
struct thread *td;
|
||||
|
||||
TDQ_LOCK_ASSERT(tdq, MA_OWNED);
|
||||
td = runq_choose(&tdq->tdq_realtime);
|
||||
if (td != NULL)
|
||||
return (td);
|
||||
td = runq_choose_from(&tdq->tdq_timeshare, tdq->tdq_ridx);
|
||||
if (td != NULL) {
|
||||
KASSERT(td->td_priority >= PRI_MIN_BATCH,
|
||||
("tdq_choose: Invalid priority on timeshare queue %d",
|
||||
td->td_priority));
|
||||
return (td);
|
||||
}
|
||||
td = runq_choose(&tdq->tdq_idle);
|
||||
if (td != NULL) {
|
||||
KASSERT(td->td_priority >= PRI_MIN_IDLE,
|
||||
("tdq_choose: Invalid priority on idle queue %d",
|
||||
td->td_priority));
|
||||
return (td);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
\end{lstlisting}
|
||||
|
||||
\subsubsection{Linux}
|
||||
\begin{lstlisting}[language=c++]
|
||||
struct sched_entity *__pick_first_entity(struct cfs_rq *cfs_rq)
|
||||
{
|
||||
struct rb_node *left = rb_first_cached(&cfs_rq->tasks_timeline);
|
||||
|
||||
if (!left)
|
||||
return NULL;
|
||||
|
||||
return rb_entry(left, struct sched_entity, run_node);
|
||||
}
|
||||
\end{lstlisting}
|
||||
|
||||
\subsection{Comparison}
|
||||
Looking at this code, we can see both operating systems approach to choosing a thread to schedule is very different. FreeBSD is choosing an item based on more qualifiers than Linux, such as whether the thread was made with priority settings. For Linux, the implementation of the tree means that finding the leftmost element is all that's needed to get the next item. In this instance, the overall more complex Linux scheduler actually has an easier time determining what to run next than FreeBSD, but FreeBSD allows for more flexibility when a user is writing a program about how exactly they want a thread to run.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,31 @@
|
||||
# This config is copied from overleaf so output there will match compiled output here
|
||||
|
||||
# support for the glossaries package:
|
||||
add_cus_dep('glo', 'gls', 0, 'makeglossaries');
|
||||
add_cus_dep('acn', 'acr', 0, 'makeglossaries');
|
||||
sub makeglossaries {
|
||||
system("makeglossaries \"$_[0]\"");
|
||||
}
|
||||
|
||||
# support for the nomencl package:
|
||||
add_cus_dep('nlo', 'nls', 0, 'makenlo2nls');
|
||||
sub makenlo2nls {
|
||||
system("makeindex -s nomencl.ist -o \"$_[0].nls\" \"$_[0].nlo\"");
|
||||
}
|
||||
|
||||
# from the documentation for V. 2.03 of asymptote:
|
||||
sub asy {return system("asy \"$_[0]\"");}
|
||||
add_cus_dep("asy","eps",0,"asy");
|
||||
add_cus_dep("asy","pdf",0,"asy");
|
||||
add_cus_dep("asy","tex",0,"asy");
|
||||
|
||||
# metapost rule from http://tex.stackexchange.com/questions/37134
|
||||
add_cus_dep('mp', '1', 0, 'mpost');
|
||||
sub mpost {
|
||||
my $file = $_[0];
|
||||
my ($name, $path) = fileparse($file);
|
||||
pushd($path);
|
||||
my $return = system "mpost $name";
|
||||
popd();
|
||||
return $return;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
# Makefile created by Corwin Perren
|
||||
# Generic makefile for all LaTeX projects downloaded from overleaf
|
||||
#
|
||||
# All this makefile does is call perl against latexmkrc, which is
|
||||
# the latex equivalent of make
|
||||
|
||||
LATEXMK_COMPILE_FLAGS = -pdf
|
||||
LATEXMK_CLEAN_FLAGS = -c
|
||||
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
all: latexmk_output clean
|
||||
|
||||
latexmk_output:
|
||||
perl latexmk.pl $(LATEXMK_COMPILE_FLAGS)
|
||||
mv output.pdf writing2_perrenc.pdf
|
||||
|
||||
clean:
|
||||
perl latexmk.pl $(LATEXMK_CLEAN_FLAGS)
|
||||
@@ -0,0 +1,92 @@
|
||||
\documentclass[onecolumn, draftclsnofoot, 10pt, compsoc]{IEEEtran}
|
||||
\usepackage{graphicx}
|
||||
\graphicspath{{./figures/}}
|
||||
|
||||
\usepackage{url}
|
||||
\usepackage{setspace}
|
||||
\usepackage{multicol}
|
||||
\usepackage{pdflscape}
|
||||
\usepackage{pdfpages}
|
||||
\usepackage[british]{babel}
|
||||
\usepackage{listings}
|
||||
\usepackage{xcolor}
|
||||
\usepackage{listings}
|
||||
\usepackage{hyperref}
|
||||
\usepackage{subfig}
|
||||
|
||||
\usepackage{geometry}
|
||||
\geometry{textheight=9.5in, textwidth=7in}
|
||||
|
||||
% \overfullrule=2in
|
||||
|
||||
|
||||
%Personal \newcommands
|
||||
|
||||
\definecolor{backcolor}{rgb}{0.95,0.95,0.92}
|
||||
\lstset{basicstyle=\ttfamily,
|
||||
backgroundcolor=\color{backcolor},
|
||||
showstringspaces=false,
|
||||
commentstyle=\color{red},
|
||||
keywordstyle=\color{blue},
|
||||
columns=fullflexible,
|
||||
breaklines=true,
|
||||
postbreak=\mbox{\textcolor{red}{$\hookrightarrow$}\space},
|
||||
}
|
||||
|
||||
\newcommand{\NameSigPair}[1]{
|
||||
\par
|
||||
\makebox[2.75in][r]{#1}
|
||||
\hfill
|
||||
\makebox[3.25in]{
|
||||
\makebox[2.25in]{\hrulefill}
|
||||
\hfill
|
||||
\makebox[.75in]{\hrulefill}
|
||||
}
|
||||
\par\vspace{-12pt}
|
||||
\textit{
|
||||
\tiny\noindent
|
||||
\makebox[2.75in]{}
|
||||
\hfill
|
||||
\makebox[3.25in]{
|
||||
\makebox[2.25in][r]{Signature}
|
||||
\hfill
|
||||
\makebox[.75in][r]{Date}
|
||||
}
|
||||
}
|
||||
}
|
||||
% 3. If the document is not to be signed, uncomment the command below
|
||||
\renewcommand{\NameSigPair}[1]{#1}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\begin{document}
|
||||
\begin{titlepage}
|
||||
\pagenumbering{gobble}
|
||||
\begin{singlespace}
|
||||
\par\vspace{2in}
|
||||
\centering
|
||||
\scshape{
|
||||
\huge Operating Systems II Writing 2 \par
|
||||
{\large\today}\par
|
||||
\vspace{.5in}
|
||||
\vfill
|
||||
\vspace{5pt}
|
||||
{\large Prepared by }\par
|
||||
|
||||
{\Large
|
||||
\NameSigPair{Corwin Perren}\par
|
||||
}
|
||||
\vspace{20pt}
|
||||
}
|
||||
\end{singlespace}
|
||||
\end{titlepage}
|
||||
\newpage
|
||||
\pagenumbering{arabic}
|
||||
|
||||
\input{writing/writing}
|
||||
|
||||
\end{document}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
\section{Introduction}
|
||||
For every operating system a way is needed to abstract complex physical hardware into easier to process logical items. All of these pieces of hardware perform some kind of I/O operation, whether it be memory, a graphics card, networking card, hard drive, or USB device. Abstraction layers are needed so that different providers for different hardware can conform to a standard such that developers don't need to learn a new API for every individual piece of hardware. This means that a keyboard made my Logitech will show up the same as a keyboard made by Microsoft. All the developer has to think about it interacting with a generic keyboard device and the driver abstracts away any of the hardware differences. In the following sections we'll take a look at how Windows, Linux, and FreeBSD handle their I/O as well as similarities and differences between the different operating systems.
|
||||
|
||||
\section{Individual OS IO Info}
|
||||
\subsection{Windows}
|
||||
In Windows the most common data structure for interacting with drivers and hardware devices are IRPs or I/O request packets. These IRPs are created by the I/O manager built into windows that takes in a request made by a call to a DLL, such as request to send a network packet. The IRP stores useful header information about the I/O operation such as whether the request is synchronous or not, as well as the interface to the low level driver. Once this IRP is made, it exists until access to the resource is no longer needed. Due to the complexity of some I/O devices, it's possible for the IRPs to point to another device driver rather than a hardware device. For example, if using a pen drive that is encrypted, the first would be the abstracted IRP that sees the resource as a file, but that IRP would point to the cryptography driver which would transparently provide block level encryption / decryption from a driver level. For options when it comes to encryption, the most common and most used ones are available such as RSA, AES. This largely is the case as hardware on CPUs is leveraged to do faster crypto calculations than if that processing were done without the extra hardware.
|
||||
|
||||
\subsection{Linux \& FreeBSD}
|
||||
Linux and FreeBSD both run kernels that share historical roots in Unix, meaning that the core of how I/O is handled is the same minus different naming conventions in the raw code itself. The most interesting feature of I/O on Unix based kernels is that everything is treated like a "file", or more accurately, accessed via file descriptors. This means that you can access hardware under an absolute path on the filesystem, but instead of reading and writing to a place on disk, the bytes read and written are actually massaged through kernel drivers to actually interact with the hardware. Reading and writing on Unix kernels in done in either structured (block) or unstructured (character) device modes. For block read/writes, an entire "block" (4kb for example) is sent or received at any given time. Character mode is just that, reading or writing a single character at a time. When it comes to cryptography, all the most common ones are available via the kernel such as RSA or AES. This largely is the case as hardware on CPUs is leveraged to do faster crypto calculations than if that processing were done without the extra hardware.
|
||||
|
||||
|
||||
\section{IO Comparisons}
|
||||
\subsection{Similarities}
|
||||
Due to the intense similarities between Linux and Unix, I'll only be comparing Unix-based vs. Windows here. The biggest similarity between the two operating systems is that there is abstraction from the hardware. In older computers, there was very little abstraction which made writing code, or an operating system for that matter very difficult. Everything had to be custom written to fit the exact configuration of the computer as it was on a user's table. By putting a layer of abstraction above this hardware, a single operating system or single source file could be easily ported from one computer (or even variant in the case of Linux vs Unix) to another, at the expense of processor time to manage a driver subsystem. Without this layer, computers and operating systems as we know them would be very different than what they actually are today.
|
||||
|
||||
\subsection{Differences}
|
||||
Beyond the simple fact that abstraction exists, there's very little that's similar between the way Windows handles IO vs Unix-based systems. Unix treats everything like a file, to the point that you can directly read/write to memory using /dev/mem if you have elevated privileges. Trying to do something like that on Windows would be incredibly difficult as Windows tries to hide that driver manager layer and doesn't provide easy access to hardware directly. One thing this means is that writing drivers for Linux is significantly easier and less time consuming than on Windows, as there is less overhead management of the drivers. Also, the open system source code also helps.
|
||||
Binary file not shown.
Reference in New Issue
Block a user