diff --git a/lab/vtsh/.gitignore b/lab/vtsh/.gitignore index fb90d94..8f5d964 100644 --- a/lab/vtsh/.gitignore +++ b/lab/vtsh/.gitignore @@ -6,3 +6,7 @@ build/ # Python __pycache__/ + +.idea/* + +some.bin \ No newline at end of file diff --git a/lab/vtsh/.idea/.gitignore b/lab/vtsh/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/lab/vtsh/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/lab/vtsh/.idea/codeStyles/Project.xml b/lab/vtsh/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..81469bd --- /dev/null +++ b/lab/vtsh/.idea/codeStyles/Project.xml @@ -0,0 +1,105 @@ + + + + + + + + \ No newline at end of file diff --git a/lab/vtsh/.idea/codeStyles/codeStyleConfig.xml b/lab/vtsh/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/lab/vtsh/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/lab/vtsh/.idea/editor.xml b/lab/vtsh/.idea/editor.xml new file mode 100644 index 0000000..0093ef6 --- /dev/null +++ b/lab/vtsh/.idea/editor.xml @@ -0,0 +1,344 @@ + + + + + \ No newline at end of file diff --git a/lab/vtsh/.idea/misc.xml b/lab/vtsh/.idea/misc.xml new file mode 100644 index 0000000..0b76fe5 --- /dev/null +++ b/lab/vtsh/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/lab/vtsh/.idea/modules.xml b/lab/vtsh/.idea/modules.xml new file mode 100644 index 0000000..af61fa6 --- /dev/null +++ b/lab/vtsh/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/lab/vtsh/.idea/vcs.xml b/lab/vtsh/.idea/vcs.xml new file mode 100644 index 0000000..b2bdec2 --- /dev/null +++ b/lab/vtsh/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/lab/vtsh/.idea/vtsh.iml b/lab/vtsh/.idea/vtsh.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/lab/vtsh/.idea/vtsh.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/lab/vtsh/bin/CMakeLists.txt b/lab/vtsh/bin/CMakeLists.txt index 7ef16bd..823b2f2 100644 --- a/lab/vtsh/bin/CMakeLists.txt +++ b/lab/vtsh/bin/CMakeLists.txt @@ -14,3 +14,14 @@ target_link_libraries( PRIVATE libvtsh ) + +add_executable( + cpu_linreg + cpu_linreg.c +) + +target_include_directories( + cpu_linreg + PUBLIC + . +) diff --git a/lab/vtsh/bin/cpu_linreg b/lab/vtsh/bin/cpu_linreg new file mode 100755 index 0000000..50aa45f Binary files /dev/null and b/lab/vtsh/bin/cpu_linreg differ diff --git a/lab/vtsh/bin/cpu_linreg.c b/lab/vtsh/bin/cpu_linreg.c new file mode 100644 index 0000000..2689839 --- /dev/null +++ b/lab/vtsh/bin/cpu_linreg.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include + +#define XMIN 0.0 +#define XMAX 100.0 +#define A_TRUE 2.0 +#define B_TRUE 3.0 +#define NOISE_SIGMA 0.5 + +double rand01() { + return (double)rand() / (double)RAND_MAX; +} + +void run_linreg(long long n) { + double mean_x = 0.0, mean_y = 0.0; + double m2x = 0.0, cxy = 0.0; + long long k = 0; + + for (long long i = 0; i < n; i++) { + double x = XMIN + rand01() * (XMAX - XMIN); + double noise = (rand01() - 0.5) * 2 * NOISE_SIGMA; + double y = A_TRUE * x + B_TRUE + noise; + + k++; + double dx = x - mean_x; + double dy = y - mean_y; + mean_x += dx / k; + mean_y += dy / k; + m2x += dx * (x - mean_x); + cxy += dx * (y - mean_y); + } + + double var_x = m2x / n; + double cov_xy = cxy / n; + + double a = cov_xy / var_x; + double b = mean_y - a * mean_x; + + printf("a = %.4f, b = %.4f\n", a, b); +} + +int main(int argc, char *argv[]) { + long long count = 10000000; + int repeat = 3; + + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "--count") == 0 && i + 1 < argc) { + count = atoll(argv[++i]); + } else if (strcmp(argv[i], "--repeat") == 0 && i + 1 < argc) { + repeat = atoi(argv[++i]); + } else { + printf("Unknown option: %s\n", argv[i]); + return 1; + } + } + + srand(7); + + struct timespec start, end; + clock_gettime(CLOCK_MONOTONIC, &start); + + for (int r = 1; r <= repeat; r++) { + run_linreg(count); + } + + clock_gettime(CLOCK_MONOTONIC, &end); + double total_time = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9; + printf("Total time = %.3f s\n", total_time); + + return 0; +} diff --git a/lab/vtsh/bin/ema_join.h b/lab/vtsh/bin/ema_join.h new file mode 100644 index 0000000..eba0eb7 --- /dev/null +++ b/lab/vtsh/bin/ema_join.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +typedef struct { + long long id; + char value[9]; +} Row; + +typedef struct { + long long id; + char left[9]; + char right[9]; +} JoinedRow; + +Row* load_table(const char* path, size_t* out_count); +int save_result(const char* path, const JoinedRow* rows, size_t count); +JoinedRow* nested_loop_join(const Row* left,size_t left_count,const Row* right,size_t right_count,size_t* out_count); +double seconds_between(const struct timespec* start,const struct timespec* end); diff --git a/lab/vtsh/bin/ema_join_algo.c b/lab/vtsh/bin/ema_join_algo.c new file mode 100644 index 0000000..6aaa03f --- /dev/null +++ b/lab/vtsh/bin/ema_join_algo.c @@ -0,0 +1,49 @@ +#include "ema_join.h" + +#include +#include +#include + +JoinedRow* nested_loop_join(const Row* left,size_t left_count,const Row* right,size_t right_count,size_t* out_count) { + JoinedRow* result = NULL; + size_t capacity = 0; + size_t size = 0; + + for (size_t i = 0; i < left_count; ++i) { + for (size_t j = 0; j < right_count; ++j) { + if (left[i].id == right[j].id) { + if (size == capacity) { + size_t new_capacity = (capacity == 0) ? 16 : (capacity * 2); + JoinedRow* tmp = realloc(result, new_capacity * sizeof(JoinedRow)); + if (tmp == NULL) { + fprintf(stderr, "Не хватает памяти для результата\n"); + free(result); + return NULL; + } + result = tmp; + capacity = new_capacity; + } + + result[size].id = left[i].id; + strncpy(result[size].left, left[i].value, sizeof(result[size].left) - 1); + result[size].left[sizeof(result[size].left) - 1] = '\0'; + strncpy(result[size].right, right[j].value, sizeof(result[size].right) - 1); + result[size].right[sizeof(result[size].right) - 1] = '\0'; + size++; + } + } + } + + *out_count = size; + return result; +} + +double seconds_between(const struct timespec* start, const struct timespec* end) { + time_t sec = end->tv_sec - start->tv_sec; + long nsec = end->tv_nsec - start->tv_nsec; + if (nsec < 0) { + sec -= 1; + nsec += 1000000000L; + } + return (double)sec + (double)nsec / 1e9; +} diff --git a/lab/vtsh/bin/ema_join_io.c b/lab/vtsh/bin/ema_join_io.c new file mode 100644 index 0000000..a6279d8 --- /dev/null +++ b/lab/vtsh/bin/ema_join_io.c @@ -0,0 +1,62 @@ +#include "ema_join.h" + +#include +#include +#include +#include + +Row* load_table(const char* path, size_t* out_count) { + FILE* file = fopen(path, "r"); + if (file == NULL) { + fprintf(stderr, "Не удалось открыть %s: %s\n", path, strerror(errno)); + return NULL; + } + + unsigned long long rows = 0; + if (fscanf(file, "%llu", &rows) != 1) { + fprintf(stderr, "Не удалось прочитать количество строк в %s\n", path); + fclose(file); + return NULL; + } + + Row* data = calloc(rows, sizeof(Row)); + if (data == NULL) { + fprintf(stderr, "Не хватает памяти для чтения %s\n", path); + fclose(file); + return NULL; + } + + for (unsigned long long i = 0; i < rows; ++i) { + long long id = 0; + char word[16] = {0}; + if (fscanf(file, "%lld %15s", &id, word) != 2) { + fprintf(stderr, "Строка %llu в %s некорректна\n", i + 1, path); + free(data); + fclose(file); + return NULL; + } + data[i].id = id; + strncpy(data[i].value, word, sizeof(data[i].value) - 1); + data[i].value[sizeof(data[i].value) - 1] = '\0'; + } + + fclose(file); + *out_count = (size_t)rows; + return data; +} + +int save_result(const char* path, const JoinedRow* rows, size_t count) { + FILE* file = fopen(path, "w"); + if (file == NULL) { + fprintf(stderr, "Не удалось открыть %s для записи: %s\n", path, strerror(errno)); + return -1; + } + + fprintf(file, "%zu\n", count); + for (size_t i = 0; i < count; ++i) { + fprintf(file, "%lld %s %s\n", rows[i].id, rows[i].left, rows[i].right); + } + + fclose(file); + return 0; +} diff --git a/lab/vtsh/bin/ema_join_nl.c b/lab/vtsh/bin/ema_join_nl.c new file mode 100644 index 0000000..0ac9c9b --- /dev/null +++ b/lab/vtsh/bin/ema_join_nl.c @@ -0,0 +1,84 @@ +#include "ema_join.h" + +#include +#include +#include + +static void usage(const char* prog) { + fprintf(stderr,"Использование: %s --left <файл> --right <файл> --out <файл> [--repeat N]\n",prog); +} + +int main(int argc, char* argv[]) { + const char* left_path = NULL; + const char* right_path = NULL; + const char* out_path = NULL; + int repeat = 1; + + for (int i = 1; i < argc; ++i) { + if (strcmp(argv[i], "--left") == 0 && i + 1 < argc) { + left_path = argv[++i]; + } else if (strcmp(argv[i], "--right") == 0 && i + 1 < argc) { + right_path = argv[++i]; + } else if (strcmp(argv[i], "--out") == 0 && i + 1 < argc) { + out_path = argv[++i]; + } else if (strcmp(argv[i], "--repeat") == 0 && i + 1 < argc) { + repeat = atoi(argv[++i]); + if (repeat <= 0) { + fprintf(stderr, "--repeat должен быть больше нуля\n"); + return 1; + } + } else { + usage(argv[0]); + return 1; + } + } + + if (left_path == NULL || right_path == NULL || out_path == NULL) { + usage(argv[0]); + return 1; + } + + size_t left_count = 0; + size_t right_count = 0; + Row* left = load_table(left_path, &left_count); + if (left == NULL) + return 1; + Row* right = load_table(right_path, &right_count); + if (right == NULL) { + free(left); + return 1; + } + + JoinedRow* result = NULL; + size_t result_count = 0; + + for (int i = 1; i <= repeat; ++i) { + free(result); + result = NULL; + result_count = 0; + + struct timespec start = {0}, end = {0}; + clock_gettime(CLOCK_MONOTONIC, &start); + result = nested_loop_join(left, left_count, right, right_count, &result_count); + clock_gettime(CLOCK_MONOTONIC, &end); + + if (result == NULL) { + free(left); + free(right); + return 1; + } + + printf("Итерация %d: совпадений=%zu время=%.6f с\n",i,result_count,seconds_between(&start, &end)); + } + + int rc = save_result(out_path, result, result_count); + free(result); + free(left); + free(right); + + if (rc != 0) + return 1; + + printf("Результат записан в %s\n", out_path); + return 0; +} diff --git a/lab/vtsh/bin/io_load.c b/lab/vtsh/bin/io_load.c new file mode 100644 index 0000000..637807e --- /dev/null +++ b/lab/vtsh/bin/io_load.c @@ -0,0 +1,16 @@ +#include "io_load.h" + +#include + +int main(int argc, char* argv[]) { + options_t opts; + if (parse_args(argc, argv, &opts) != 0) { + print_usage(argv[0]); + return 1; + } + + if (run_io_workload(&opts) != 0) + return 1; + + return 0; +} diff --git a/lab/vtsh/bin/io_load.h b/lab/vtsh/bin/io_load.h new file mode 100644 index 0000000..537690a --- /dev/null +++ b/lab/vtsh/bin/io_load.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include + +typedef enum { + MODE_READ, + MODE_WRITE +} io_mode_t; + +typedef enum { + ORDER_SEQUENCE, + ORDER_RANDOM +} io_order_t; + +typedef struct { + io_mode_t mode; + size_t block_size; + size_t block_count; + const char* path; + int repeat; + bool use_direct; + io_order_t order; + bool range_set; + off_t range_start; + off_t range_end; +} options_t; + +void print_usage(const char* prog); +int parse_args(int argc, char* argv[], options_t* opts); +int run_io_workload(const options_t* opts); diff --git a/lab/vtsh/bin/io_load_args.c b/lab/vtsh/bin/io_load_args.c new file mode 100644 index 0000000..17ce494 --- /dev/null +++ b/lab/vtsh/bin/io_load_args.c @@ -0,0 +1,125 @@ +#include "io_load.h" + +#include +#include +#include +#include + +static bool parse_range(const char* text, off_t* start, off_t* end, bool* range_set) { + const char* dash = strchr(text, '-'); + if (dash == NULL) + return false; + + char left[32]; + char right[32]; + size_t left_len = (size_t)(dash - text); + size_t right_len = strlen(dash + 1); + if (left_len == 0 || right_len == 0 || + left_len >= sizeof(left) || right_len >= sizeof(right)) + return false; + + memcpy(left, text, left_len); + left[left_len] = '\0'; + memcpy(right, dash + 1, right_len + 1); + + errno = 0; + long long start_val = strtoll(left, NULL, 10); + long long end_val = strtoll(right, NULL, 10); + if (errno != 0 || start_val < 0 || end_val < 0) + return false; + + *start = (off_t)start_val; + *end = (off_t)end_val; + *range_set = !(start_val == 0 && end_val == 0); + return true; +} + +void print_usage(const char* prog) { + fprintf(stderr, + "Usage: %s --rw --block_size --block_count \n" + " --file [--range start-end] [--direct on|off]\n" + " [--type sequence|random] [--repeat N]\n", + prog); +} + +int parse_args(int argc, char* argv[], options_t* opts) { + opts->mode = MODE_READ; + opts->block_size = 4096; + opts->block_count = 1024; + opts->path = NULL; + opts->repeat = 1; + opts->use_direct = false; + opts->order = ORDER_SEQUENCE; + opts->range_set = false; + opts->range_start = 0; + opts->range_end = 0; + + for (int i = 1; i < argc; ++i) { + if (strcmp(argv[i], "--rw") == 0 && i + 1 < argc) { + const char* mode = argv[++i]; + if (strcmp(mode, "read") == 0) { + opts->mode = MODE_READ; + } else if (strcmp(mode, "write") == 0) { + opts->mode = MODE_WRITE; + } else { + fprintf(stderr, "Unknown --rw value: %s\n", mode); + return -1; + } + } else if (strcmp(argv[i], "--block_size") == 0 && i + 1 < argc) { + opts->block_size = (size_t)strtoull(argv[++i], NULL, 10); + if (opts->block_size == 0) { + fprintf(stderr, "block_size must be > 0\n"); + return -1; + } + } else if (strcmp(argv[i], "--block_count") == 0 && i + 1 < argc) { + opts->block_count = (size_t)strtoull(argv[++i], NULL, 10); + if (opts->block_count == 0) { + fprintf(stderr, "block_count must be > 0\n"); + return -1; + } + } else if (strcmp(argv[i], "--file") == 0 && i + 1 < argc) { + opts->path = argv[++i]; + } else if (strcmp(argv[i], "--repeat") == 0 && i + 1 < argc) { + opts->repeat = atoi(argv[++i]); + if (opts->repeat <= 0) { + fprintf(stderr, "repeat must be > 0\n"); + return -1; + } + } else if (strcmp(argv[i], "--direct") == 0 && i + 1 < argc) { + const char* val = argv[++i]; + if (strcmp(val, "on") == 0) { + opts->use_direct = true; + } else if (strcmp(val, "off") == 0) { + opts->use_direct = false; + } else { + fprintf(stderr, "--direct accepts on/off\n"); + return -1; + } + } else if (strcmp(argv[i], "--type") == 0 && i + 1 < argc) { + const char* val = argv[++i]; + if (strcmp(val, "sequence") == 0) { + opts->order = ORDER_SEQUENCE; + } else if (strcmp(val, "random") == 0) { + opts->order = ORDER_RANDOM; + } else { + fprintf(stderr, "--type accepts sequence/random\n"); + return -1; + } + } else if (strcmp(argv[i], "--range") == 0 && i + 1 < argc) { + if (!parse_range(argv[++i], &opts->range_start, &opts->range_end, &opts->range_set)) { + fprintf(stderr, "Invalid range format\n"); + return -1; + } + } else { + fprintf(stderr, "Unknown argument: %s\n", argv[i]); + return -1; + } + } + + if (opts->path == NULL) { + fprintf(stderr, "--file is required\n"); + return -1; + } + + return 0; +} diff --git a/lab/vtsh/bin/io_load_runner.c b/lab/vtsh/bin/io_load_runner.c new file mode 100644 index 0000000..9d2a07a --- /dev/null +++ b/lab/vtsh/bin/io_load_runner.c @@ -0,0 +1,176 @@ +#include "io_load.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void* allocate_buffer(size_t size) { + void* buffer = malloc(size); + if (buffer == NULL) + fprintf(stderr, "malloc failed\n"); + return buffer; +} + +static double seconds_between(const struct timespec* start, + const struct timespec* end) { + time_t sec = end->tv_sec - start->tv_sec; + long nsec = end->tv_nsec - start->tv_nsec; + if (nsec < 0) { + sec -= 1; + nsec += 1000000000L; + } + return (double)sec + (double)nsec / 1e9; +} + +static int check_range(const options_t* opts, const struct stat* st) { + off_t range_start = opts->range_start; + off_t range_end = opts->range_end; + + if (!opts->range_set) { + range_start = 0; + if (opts->mode == MODE_READ) { + range_end = st->st_size; + } else { + range_end = range_start + (off_t)(opts->block_size * opts->block_count); + } + } + + if (opts->mode == MODE_READ && range_end > st->st_size) { + fprintf(stderr, "Range exceeds file size for read mode\n"); + return -1; + } + + if (range_end <= range_start) { + fprintf(stderr, "Invalid range\n"); + return -1; + } + + off_t span = range_end - range_start; + if (opts->order == ORDER_SEQUENCE && + span < (off_t)(opts->block_size * opts->block_count)) { + fprintf(stderr, "Range is too small for sequential access\n"); + return -1; + } + + return 0; +} + +static off_t pick_offset(const options_t* opts, off_t range_start, size_t index) { + if (opts->order == ORDER_RANDOM) { + off_t range_bytes = opts->range_end - opts->range_start; + if (range_bytes < (off_t)opts->block_size) + return opts->range_start; + + off_t slots = range_bytes / (off_t)opts->block_size; + if (slots <= 0) + slots = 1; + off_t slot = (off_t)(rand() % (int)slots); + return opts->range_start + slot * (off_t)opts->block_size; + } + + return range_start + (off_t)(index * opts->block_size); +} + +int run_io_workload(const options_t* opts) { + int flags = (opts->mode == MODE_READ) ? O_RDONLY : (O_WRONLY | O_CREAT); + int fd = open(opts->path, flags, 0666); + if (fd < 0) { + fprintf(stderr, "Failed to open %s: %s\n", opts->path, strerror(errno)); + return 1; + } + +#if defined(F_NOCACHE) + if (opts->use_direct && fcntl(fd, F_NOCACHE, 1) != 0) + fprintf(stderr, "fcntl failed: %s\n", strerror(errno)); +#else + if (opts->use_direct) + fprintf(stderr, "Warning: F_NOCACHE not supported on this platform\n"); +#endif + + struct stat st; + if (fstat(fd, &st) != 0) { + fprintf(stderr, "fstat failed: %s\n", strerror(errno)); + close(fd); + return 1; + } + + options_t local_opts = *opts; + if (!local_opts.range_set) { + local_opts.range_start = 0; + if (local_opts.mode == MODE_READ) + local_opts.range_end = st.st_size; + else + local_opts.range_end = local_opts.range_start + (off_t)(local_opts.block_size * local_opts.block_count); + } + + if (check_range(&local_opts, &st) != 0) { + close(fd); + return 1; + } + + void* buffer = allocate_buffer(local_opts.block_size); + if (buffer == NULL) { + close(fd); + return 1; + } + + if (local_opts.mode == MODE_WRITE) { + for (size_t i = 0; i < local_opts.block_size; ++i) + ((unsigned char*)buffer)[i] = (unsigned char)('A' + (i % 26)); + } + + srand(0); + + struct timespec total_start = {0}, total_end = {0}; + clock_gettime(CLOCK_MONOTONIC, &total_start); + + for (int r = 0; r < local_opts.repeat; ++r) { + struct timespec start, end; + clock_gettime(CLOCK_MONOTONIC, &start); + + for (size_t i = 0; i < local_opts.block_count; ++i) { + off_t offset = pick_offset(&local_opts, local_opts.range_start, i); + ssize_t done; + if (local_opts.mode == MODE_READ) { + done = pread(fd, buffer, local_opts.block_size, offset); + } else { + done = pwrite(fd, buffer, local_opts.block_size, offset); + } + if (done < 0) { + fprintf(stderr, "I/O error at block %zu: %s\n", i, strerror(errno)); + free(buffer); + close(fd); + return 1; + } + if ((size_t)done != local_opts.block_size) { + fprintf(stderr, "Short transfer at block %zu\n", i); + free(buffer); + close(fd); + return 1; + } + } + + clock_gettime(CLOCK_MONOTONIC, &end); + time_t sec = end.tv_sec - start.tv_sec; + long nsec = end.tv_nsec - start.tv_nsec; + if (nsec < 0) { + sec -= 1; + nsec += 1000000000L; + } + double elapsed = (double)sec + (double)nsec / 1e9; + printf("Iteration %d: blocks=%zu size=%zu bytes time=%.6f s\n", r + 1, local_opts.block_count, local_opts.block_size, elapsed); + } + + clock_gettime(CLOCK_MONOTONIC, &total_end); + printf("Total time: %.6f s\n", seconds_between(&total_start, &total_end)); + + free(buffer); + close(fd); + return 0; +} diff --git a/lab/vtsh/bin/main b/lab/vtsh/bin/main new file mode 100755 index 0000000..8ccf644 Binary files /dev/null and b/lab/vtsh/bin/main differ diff --git a/lab/vtsh/bin/main.c b/lab/vtsh/bin/main.c index fd9b122..ed7015e 100644 --- a/lab/vtsh/bin/main.c +++ b/lab/vtsh/bin/main.c @@ -1,7 +1,116 @@ #include -#include +#include +#include +#include +#include +#include +#include + +#define MAX_INPUT 1024 +#define MAX_ARGS 64 + +static char* skip_spaces(char* s) { + while (*s == ' ' || *s == '\t') + s++; + return s; +} + +int run_command(char *cmd) { + char *args[MAX_ARGS]; + pid_t pid; + int status; + + int argc = 0; + char *token = strtok(cmd, " \t"); + while (token != NULL && argc < MAX_ARGS - 1) { + args[argc++] = token; + token = strtok(NULL, " \t"); + } + args[argc] = NULL; + + if (argc == 0) + return 0; + + if (strcmp(args[0], "exit") == 0) + exit(0); + + struct timespec start = {0}, end = {0}; + clock_gettime(CLOCK_MONOTONIC, &start); + + pid = vfork(); + if (pid < 0) + _exit(1); + + if (pid == 0) { + execvp(args[0], args); + const char msg[] = "Command not found\n"; + write(STDOUT_FILENO, msg, sizeof(msg) - 1); + _exit(127); + } + + if (waitpid(pid, &status, 0) < 0) + return 1; + + clock_gettime(CLOCK_MONOTONIC, &end); + time_t sec = end.tv_sec - start.tv_sec; + long nsec = end.tv_nsec - start.tv_nsec; + if (nsec < 0) { + sec -= 1; + nsec += 1000000000L; + } + double time_spent = (double)sec + (double)nsec / 1e9; + fprintf(stderr, "time=%.6f\n", time_spent); + + if (WIFEXITED(status)) + return WEXITSTATUS(status); + if (WIFSIGNALED(status)) + return 128 + WTERMSIG(status); + return 1; +} int main() { - printf("%s", vtsh_prompt()); - printf("Hello, world!\n"); + char input[MAX_INPUT]; + setvbuf(stdin, NULL, _IONBF, 0); + + while (1) { + if (fgets(input, sizeof(input), stdin) == NULL) + break; + + input[strcspn(input, "\n")] = '\0'; + char *cmd = skip_spaces(input); + if (*cmd == '\0') + continue; + + int code = 0; + + while (cmd != NULL && *cmd != '\0') { + char *and_ptr = strstr(cmd, "&&"); + + if (and_ptr != NULL) { + *and_ptr = '\0'; + } + + char *segment = skip_spaces(cmd); + if (*segment == '\0') { + fprintf(stderr, "syntax error: empty command\n"); + break; + } + + code = run_command(segment); + + if (code != 0) + break; + + if (and_ptr == NULL) + break; + + cmd = skip_spaces(and_ptr + 2); + if (*cmd == '\0') { + fprintf(stderr, "syntax error: trailing &&\n"); + break; + } + } + } + + return 0; } diff --git a/lab/vtsh/joined.tbl b/lab/vtsh/joined.tbl new file mode 100644 index 0000000..d94eddb --- /dev/null +++ b/lab/vtsh/joined.tbl @@ -0,0 +1,4 @@ +3 +1 alpha___ one_____ +2 bravo___ two_____ +3 charlie_ three___ diff --git a/lab/vtsh/left.tbl b/lab/vtsh/left.tbl new file mode 100644 index 0000000..27644cf --- /dev/null +++ b/lab/vtsh/left.tbl @@ -0,0 +1,4 @@ +3 +1 alpha___ +2 bravo___ +3 charlie_ diff --git a/lab/vtsh/out.bin b/lab/vtsh/out.bin new file mode 100644 index 0000000..fecb092 Binary files /dev/null and b/lab/vtsh/out.bin differ diff --git a/lab/vtsh/right.tbl b/lab/vtsh/right.tbl new file mode 100644 index 0000000..d2895e2 --- /dev/null +++ b/lab/vtsh/right.tbl @@ -0,0 +1,5 @@ +4 +1 one_____ +3 three___ +4 four____ +2 two_____ diff --git a/lab/vtsh/test/shell b/lab/vtsh/test/shell new file mode 120000 index 0000000..86ff261 --- /dev/null +++ b/lab/vtsh/test/shell @@ -0,0 +1 @@ +../build/bin/vtsh \ No newline at end of file diff --git a/lab/vtsh/test/test_redirection.py b/lab/vtsh/test/test_redirection.py index cb14495..1759e4b 100644 --- a/lab/vtsh/test/test_redirection.py +++ b/lab/vtsh/test/test_redirection.py @@ -4,7 +4,7 @@ REQUIRED_REDIRECTION_FUNCTIONALITY = False -@unittest.skipIf(not REQUIRED_REDIRECTION_FUNCTIONALITY, +@unittest.skipIf(not REQUIRED_REDIRECTION_FUNCTIONALITY, ("Redirection functionality is not required in the task. " "This functionality is for an additional task.")) class TestShellRedirection(BaseShellTest):