A3 🎉
This commit is contained in:
BIN
A1/src.zip
Normal file
BIN
A1/src.zip
Normal file
Binary file not shown.
23
A2/Makefile
Normal file
23
A2/Makefile
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
CC=gcc
|
||||||
|
CFLAGS=-g -Wall -Wextra -pedantic -std=gnu99 -pthread
|
||||||
|
EXAMPLES=fibs fauxgrep fauxgrep-mt fhistogram fhistogram-mt
|
||||||
|
|
||||||
|
.PHONY: all test clean ../src.zip
|
||||||
|
|
||||||
|
all: $(TESTS) $(EXAMPLES)
|
||||||
|
|
||||||
|
job_queue.o: job_queue.c job_queue.h
|
||||||
|
$(CC) -c job_queue.c $(CFLAGS)
|
||||||
|
|
||||||
|
%: %.c job_queue.o
|
||||||
|
$(CC) -o $@ $^ $(CFLAGS)
|
||||||
|
|
||||||
|
test: $(TESTS)
|
||||||
|
@set e; for test in $(TESTS); do echo ./$$test; ./$$test; done
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(TESTS) $(EXAMPLES) *.o core
|
||||||
|
|
||||||
|
../src.zip:
|
||||||
|
make clean
|
||||||
|
cd .. && zip src.zip -r src
|
87
A2/fauxgrep-mt.c
Normal file
87
A2/fauxgrep-mt.c
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
// Setting _DEFAULT_SOURCE is necessary to activate visibility of
|
||||||
|
// certain header file contents on GNU/Linux systems.
|
||||||
|
#define _DEFAULT_SOURCE
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fts.h>
|
||||||
|
|
||||||
|
// err.h contains various nonstandard BSD extensions, but they are
|
||||||
|
// very handy.
|
||||||
|
#include <err.h>
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "job_queue.h"
|
||||||
|
|
||||||
|
int main(int argc, char * const *argv) {
|
||||||
|
if (argc < 2) {
|
||||||
|
err(1, "usage: [-n INT] STRING paths...");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_threads = 1;
|
||||||
|
char const *needle = argv[1];
|
||||||
|
char * const *paths = &argv[2];
|
||||||
|
|
||||||
|
|
||||||
|
if (argc > 3 && strcmp(argv[1], "-n") == 0) {
|
||||||
|
// Since atoi() simply returns zero on syntax errors, we cannot
|
||||||
|
// distinguish between the user entering a zero, or some
|
||||||
|
// non-numeric garbage. In fact, we cannot even tell whether the
|
||||||
|
// given option is suffixed by garbage, i.e. '123foo' returns
|
||||||
|
// '123'. A more robust solution would use strtol(), but its
|
||||||
|
// interface is more complicated, so here we are.
|
||||||
|
num_threads = atoi(argv[2]);
|
||||||
|
|
||||||
|
if (num_threads < 1) {
|
||||||
|
err(1, "invalid thread count: %s", argv[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
needle = argv[3];
|
||||||
|
paths = &argv[4];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
needle = argv[1];
|
||||||
|
paths = &argv[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(0); // Initialise the job queue and some worker threads here.
|
||||||
|
|
||||||
|
// FTS_LOGICAL = follow symbolic links
|
||||||
|
// FTS_NOCHDIR = do not change the working directory of the process
|
||||||
|
//
|
||||||
|
// (These are not particularly important distinctions for our simple
|
||||||
|
// uses.)
|
||||||
|
int fts_options = FTS_LOGICAL | FTS_NOCHDIR;
|
||||||
|
|
||||||
|
FTS *ftsp;
|
||||||
|
if ((ftsp = fts_open(paths, fts_options, NULL)) == NULL) {
|
||||||
|
err(1, "fts_open() failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FTSENT *p;
|
||||||
|
while ((p = fts_read(ftsp)) != NULL) {
|
||||||
|
switch (p->fts_info) {
|
||||||
|
case FTS_D:
|
||||||
|
break;
|
||||||
|
case FTS_F:
|
||||||
|
assert(0); // Process the file p->fts_path, somehow.
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fts_close(ftsp);
|
||||||
|
|
||||||
|
assert(0); // Shut down the job queue and the worker threads here.
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
82
A2/fauxgrep.c
Normal file
82
A2/fauxgrep.c
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
// Setting _DEFAULT_SOURCE is necessary to activate visibility of
|
||||||
|
// certain header file contents on GNU/Linux systems.
|
||||||
|
#define _DEFAULT_SOURCE
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fts.h>
|
||||||
|
|
||||||
|
// err.h contains various nonstandard BSD extensions, but they are
|
||||||
|
// very handy.
|
||||||
|
#include <err.h>
|
||||||
|
|
||||||
|
int fauxgrep_file(char const *needle, char const *path) {
|
||||||
|
FILE *f = fopen(path, "r");
|
||||||
|
|
||||||
|
if (f == NULL) {
|
||||||
|
warn("failed to open %s", path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *line = NULL;
|
||||||
|
size_t linelen = 0;
|
||||||
|
int lineno = 1;
|
||||||
|
|
||||||
|
while (getline(&line, &linelen, f) != -1) {
|
||||||
|
if (strstr(line, needle) != NULL) {
|
||||||
|
printf("%s:%d: %s", path, lineno, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
lineno++;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(line);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char * const *argv) {
|
||||||
|
if (argc < 2) {
|
||||||
|
err(1, "usage: STRING paths...");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
char const *needle = argv[1];
|
||||||
|
char * const *paths = &argv[2];
|
||||||
|
|
||||||
|
// FTS_LOGICAL = follow symbolic links
|
||||||
|
// FTS_NOCHDIR = do not change the working directory of the process
|
||||||
|
//
|
||||||
|
// (These are not particularly important distinctions for our simple
|
||||||
|
// uses.)
|
||||||
|
int fts_options = FTS_LOGICAL | FTS_NOCHDIR;
|
||||||
|
|
||||||
|
FTS *ftsp;
|
||||||
|
if ((ftsp = fts_open(paths, fts_options, NULL)) == NULL) {
|
||||||
|
err(1, "fts_open() failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FTSENT *p;
|
||||||
|
while ((p = fts_read(ftsp)) != NULL) {
|
||||||
|
switch (p->fts_info) {
|
||||||
|
case FTS_D:
|
||||||
|
break;
|
||||||
|
case FTS_F:
|
||||||
|
fauxgrep_file(needle, p->fts_path);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fts_close(ftsp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
87
A2/fhistogram-mt.c
Normal file
87
A2/fhistogram-mt.c
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
// Setting _DEFAULT_SOURCE is necessary to activate visibility of
|
||||||
|
// certain header file contents on GNU/Linux systems.
|
||||||
|
#define _DEFAULT_SOURCE
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fts.h>
|
||||||
|
|
||||||
|
#include "job_queue.h"
|
||||||
|
|
||||||
|
pthread_mutex_t stdout_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
// err.h contains various nonstandard BSD extensions, but they are
|
||||||
|
// very handy.
|
||||||
|
#include <err.h>
|
||||||
|
|
||||||
|
#include "histogram.h"
|
||||||
|
|
||||||
|
int main(int argc, char * const *argv) {
|
||||||
|
if (argc < 2) {
|
||||||
|
err(1, "usage: paths...");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_threads = 1;
|
||||||
|
char * const *paths = &argv[1];
|
||||||
|
|
||||||
|
if (argc > 3 && strcmp(argv[1], "-n") == 0) {
|
||||||
|
// Since atoi() simply returns zero on syntax errors, we cannot
|
||||||
|
// distinguish between the user entering a zero, or some
|
||||||
|
// non-numeric garbage. In fact, we cannot even tell whether the
|
||||||
|
// given option is suffixed by garbage, i.e. '123foo' returns
|
||||||
|
// '123'. A more robust solution would use strtol(), but its
|
||||||
|
// interface is more complicated, so here we are.
|
||||||
|
num_threads = atoi(argv[2]);
|
||||||
|
|
||||||
|
if (num_threads < 1) {
|
||||||
|
err(1, "invalid thread count: %s", argv[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
paths = &argv[3];
|
||||||
|
} else {
|
||||||
|
paths = &argv[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(0); // Initialise the job queue and some worker threads here.
|
||||||
|
|
||||||
|
// FTS_LOGICAL = follow symbolic links
|
||||||
|
// FTS_NOCHDIR = do not change the working directory of the process
|
||||||
|
//
|
||||||
|
// (These are not particularly important distinctions for our simple
|
||||||
|
// uses.)
|
||||||
|
int fts_options = FTS_LOGICAL | FTS_NOCHDIR;
|
||||||
|
|
||||||
|
FTS *ftsp;
|
||||||
|
if ((ftsp = fts_open(paths, fts_options, NULL)) == NULL) {
|
||||||
|
err(1, "fts_open() failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FTSENT *p;
|
||||||
|
while ((p = fts_read(ftsp)) != NULL) {
|
||||||
|
switch (p->fts_info) {
|
||||||
|
case FTS_D:
|
||||||
|
break;
|
||||||
|
case FTS_F:
|
||||||
|
assert(0); // Process the file p->fts_path, somehow.
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fts_close(ftsp);
|
||||||
|
|
||||||
|
assert(0); // Shut down the job queue and the worker threads here.
|
||||||
|
|
||||||
|
move_lines(9);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
93
A2/fhistogram.c
Normal file
93
A2/fhistogram.c
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// Setting _DEFAULT_SOURCE is necessary to activate visibility of
|
||||||
|
// certain header file contents on GNU/Linux systems.
|
||||||
|
#define _DEFAULT_SOURCE
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fts.h>
|
||||||
|
|
||||||
|
// err.h contains various nonstandard BSD extensions, but they are
|
||||||
|
// very handy.
|
||||||
|
#include <err.h>
|
||||||
|
|
||||||
|
#include "histogram.h"
|
||||||
|
|
||||||
|
int global_histogram[8] = { 0 };
|
||||||
|
|
||||||
|
int fhistogram(char const *path) {
|
||||||
|
FILE *f = fopen(path, "r");
|
||||||
|
|
||||||
|
int local_histogram[8] = { 0 };
|
||||||
|
|
||||||
|
if (f == NULL) {
|
||||||
|
fflush(stdout);
|
||||||
|
warn("failed to open %s", path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
char c;
|
||||||
|
while (fread(&c, sizeof(c), 1, f) == 1) {
|
||||||
|
i++;
|
||||||
|
update_histogram(local_histogram, c);
|
||||||
|
if ((i % 100000) == 0) {
|
||||||
|
merge_histogram(local_histogram, global_histogram);
|
||||||
|
print_histogram(global_histogram);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
merge_histogram(local_histogram, global_histogram);
|
||||||
|
print_histogram(global_histogram);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char * const *argv) {
|
||||||
|
if (argc < 2) {
|
||||||
|
err(1, "usage: paths...");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
char * const *paths = &argv[1];
|
||||||
|
|
||||||
|
// FTS_LOGICAL = follow symbolic links
|
||||||
|
// FTS_NOCHDIR = do not change the working directory of the process
|
||||||
|
//
|
||||||
|
// (These are not particularly important distinctions for our simple
|
||||||
|
// uses.)
|
||||||
|
int fts_options = FTS_LOGICAL | FTS_NOCHDIR;
|
||||||
|
|
||||||
|
FTS *ftsp;
|
||||||
|
if ((ftsp = fts_open(paths, fts_options, NULL)) == NULL) {
|
||||||
|
err(1, "fts_open() failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FTSENT *p;
|
||||||
|
while ((p = fts_read(ftsp)) != NULL) {
|
||||||
|
switch (p->fts_info) {
|
||||||
|
case FTS_D:
|
||||||
|
break;
|
||||||
|
case FTS_F:
|
||||||
|
fhistogram(p->fts_path);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fts_close(ftsp);
|
||||||
|
|
||||||
|
move_lines(9);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
122
A2/fibs.c
Normal file
122
A2/fibs.c
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
// This program reads a newline-separated sequence of integers from
|
||||||
|
// standard input. For each such integer, the corresponding Fibonacci
|
||||||
|
// number is printed. This is similar to the programs we saw at the
|
||||||
|
// November 20 lecture.
|
||||||
|
|
||||||
|
// Setting _DEFAULT_SOURCE is necessary to activate visibility of
|
||||||
|
// certain header file contents on GNU/Linux systems.
|
||||||
|
#define _DEFAULT_SOURCE
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fts.h>
|
||||||
|
|
||||||
|
// err.h contains various nonstandard BSD extensions, but they are
|
||||||
|
// very handy.
|
||||||
|
#include <err.h>
|
||||||
|
|
||||||
|
#include "job_queue.h"
|
||||||
|
|
||||||
|
// Whenever we print to the screen, we will first lock this mutex.
|
||||||
|
// This ensures that multiple threads do not try to print
|
||||||
|
// concurrently.
|
||||||
|
pthread_mutex_t stdout_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
// A simple recursive (inefficient) implementation of the Fibonacci
|
||||||
|
// function.
|
||||||
|
int fib (int n) {
|
||||||
|
if (n < 2) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return fib(n-1) + fib(n-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function converts a line to an integer, computes the
|
||||||
|
// corresponding Fibonacci number, then prints the result to the
|
||||||
|
// screen.
|
||||||
|
void fib_line(const char *line) {
|
||||||
|
int n = atoi(line);
|
||||||
|
int fibn = fib(n);
|
||||||
|
assert(pthread_mutex_lock(&stdout_mutex) == 0);
|
||||||
|
printf("fib(%d) = %d\n", n, fibn);
|
||||||
|
assert(pthread_mutex_unlock(&stdout_mutex) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each thread will run this function. The thread argument is a
|
||||||
|
// pointer to a job queue.
|
||||||
|
void* worker(void *arg) {
|
||||||
|
struct job_queue *jq = arg;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
char *line;
|
||||||
|
if (job_queue_pop(jq, (void**)&line) == 0) {
|
||||||
|
fib_line(line);
|
||||||
|
free(line);
|
||||||
|
} else {
|
||||||
|
// If job_queue_pop() returned non-zero, that means the queue is
|
||||||
|
// being killed (or some other error occured). In any case,
|
||||||
|
// that means it's time for this thread to die.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char * const *argv) {
|
||||||
|
int num_threads = 1;
|
||||||
|
|
||||||
|
if (argc == 3 && strcmp(argv[1], "-n") == 0) {
|
||||||
|
// Since atoi() simply returns zero on syntax errors, we cannot
|
||||||
|
// distinguish between the user entering a zero, or some
|
||||||
|
// non-numeric garbage. In fact, we cannot even tell whether the
|
||||||
|
// given option is suffixed by garbage, i.e. '123foo' returns
|
||||||
|
// '123'. A more robust solution would use strtol(), but its
|
||||||
|
// interface is more complicated, so here we are.
|
||||||
|
num_threads = atoi(argv[2]);
|
||||||
|
|
||||||
|
if (num_threads < 1) {
|
||||||
|
err(1, "invalid thread count: %s", argv[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create job queue.
|
||||||
|
struct job_queue jq;
|
||||||
|
job_queue_init(&jq, 64);
|
||||||
|
|
||||||
|
// Start up the worker threads.
|
||||||
|
pthread_t *threads = calloc(num_threads, sizeof(pthread_t));
|
||||||
|
for (int i = 0; i < num_threads; i++) {
|
||||||
|
if (pthread_create(&threads[i], NULL, &worker, &jq) != 0) {
|
||||||
|
err(1, "pthread_create() failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Now read lines from stdin until EOF.
|
||||||
|
char *line = NULL;
|
||||||
|
ssize_t line_len;
|
||||||
|
size_t buf_len = 0;
|
||||||
|
while ((line_len = getline(&line, &buf_len, stdin)) != -1) {
|
||||||
|
job_queue_push(&jq, (void*)strdup(line));
|
||||||
|
}
|
||||||
|
free(line);
|
||||||
|
|
||||||
|
// Destroy the queue.
|
||||||
|
job_queue_destroy(&jq);
|
||||||
|
|
||||||
|
// Wait for all threads to finish. This is important, at some may
|
||||||
|
// still be working on their job.
|
||||||
|
for (int i = 0; i < num_threads; i++) {
|
||||||
|
if (pthread_join(threads[i], NULL) != 0) {
|
||||||
|
err(1, "pthread_join() failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
71
A2/histogram.h
Normal file
71
A2/histogram.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// This header file contains not just function prototypes, but also
|
||||||
|
// the definitions. This means it does not need to be compiled
|
||||||
|
// separately.
|
||||||
|
//
|
||||||
|
// You should not need to modify this file.
|
||||||
|
|
||||||
|
#ifndef HISTOGRAM_H
|
||||||
|
#define HISTOGRAM_H
|
||||||
|
|
||||||
|
// Move the cursor down 'n' lines. Negative 'n' supported.
|
||||||
|
static void move_lines(int n) {
|
||||||
|
if (n < 0) {
|
||||||
|
printf("\033[%dA", -n);
|
||||||
|
} else {
|
||||||
|
printf("\033[%dB", n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear from cursor to end of line.
|
||||||
|
static void clear_line() {
|
||||||
|
printf("\033[K");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print a visual representation of a histogram to the screen. After
|
||||||
|
// printing, the cursor is moved back to the beginning of the output.
|
||||||
|
// This means that next time print_histogram() is called, the previous
|
||||||
|
// output will be overwritten.
|
||||||
|
static void print_histogram(int histogram[8]) {
|
||||||
|
int64_t bits_seen = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
bits_seen += histogram[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
clear_line();
|
||||||
|
printf("Bit %d: ", i);
|
||||||
|
|
||||||
|
double proportion = histogram[i] / ((double)bits_seen);
|
||||||
|
for (int i = 0; i < 60*proportion; i++) {
|
||||||
|
printf("*");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_line();
|
||||||
|
printf("%ld bits processed.\n", (long)bits_seen);
|
||||||
|
move_lines(-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge the former histogram into the latter, setting the former to
|
||||||
|
// zero in the process.
|
||||||
|
static void merge_histogram(int from[8], int to[8]) {
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
to[i] += from[i];
|
||||||
|
from[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the histogram with the bits of a byte.
|
||||||
|
static void update_histogram(int histogram[8], unsigned char byte) {
|
||||||
|
// For all bits in a byte...
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
// count if bit 'i' is set.
|
||||||
|
if (byte & (1<<i)) {
|
||||||
|
histogram[i]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
21
A2/job_queue.c
Normal file
21
A2/job_queue.c
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "job_queue.h"
|
||||||
|
|
||||||
|
int job_queue_init(struct job_queue *job_queue, int capacity) {
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int job_queue_destroy(struct job_queue *job_queue) {
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int job_queue_push(struct job_queue *job_queue, void *data) {
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int job_queue_pop(struct job_queue *job_queue, void **data) {
|
||||||
|
assert(0);
|
||||||
|
}
|
30
A2/job_queue.h
Normal file
30
A2/job_queue.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#ifndef JOB_QUEUE_H
|
||||||
|
#define JOB_QUEUE_H
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
struct job_queue {
|
||||||
|
int dummy;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialise a job queue with the given capacity. The queue starts out
|
||||||
|
// empty. Returns non-zero on error.
|
||||||
|
int job_queue_init(struct job_queue *job_queue, int capacity);
|
||||||
|
|
||||||
|
// Destroy the job queue. Blocks until the queue is empty before it
|
||||||
|
// is destroyed.
|
||||||
|
int job_queue_destroy(struct job_queue *job_queue);
|
||||||
|
|
||||||
|
// Push an element onto the end of the job queue. Blocks if the
|
||||||
|
// job_queue is full (its size is equal to its capacity). Returns
|
||||||
|
// non-zero on error. It is an error to push a job onto a queue that
|
||||||
|
// has been destroyed.
|
||||||
|
int job_queue_push(struct job_queue *job_queue, void *data);
|
||||||
|
|
||||||
|
// Pop an element from the front of the job queue. Blocks if the
|
||||||
|
// job_queue contains zero elements. Returns non-zero on error. If
|
||||||
|
// job_queue_destroy() has been called (possibly after the call to
|
||||||
|
// job_queue_pop() blocked), this function will return -1.
|
||||||
|
int job_queue_pop(struct job_queue *job_queue, void **data);
|
||||||
|
|
||||||
|
#endif
|
Reference in New Issue
Block a user