From 64707e46a4075d54b0d5117ee047a026a87c6879 Mon Sep 17 00:00:00 2001 From: Nick Downing Date: Sat, 18 May 2019 10:17:59 +1000 Subject: [PATCH] Implement FUZIX build, reduces block sizes, simplifies hash function, fixes rassert issues --- Makefile | 8 ++++--- block_pool.c | 1 + core.c | 1 + pp.sh => cpp.sh | 10 ++++---- fuzix_fs.c | 22 +++++++++++++++--- fuzix_fs.h | 58 ++++++++++++++++++++++++---------------------- gen.sh | 17 +++++++++----- pool_test_run.c | 1 + process.c | 7 +++--- process.h | 7 +++++- process_test_gen.c | 5 ++++ process_test_run.c | 41 ++++++++++++++++++++++++++++++-- rassert.h | 31 ++++++++++++++++++------- swap.c | 1 + 14 files changed, 151 insertions(+), 59 deletions(-) rename pp.sh => cpp.sh (77%) diff --git a/Makefile b/Makefile index ac390d8..9e2e47d 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,9 @@ CFLAGS=-g -Wall -#CPPFLAGS=-DNDEBUG +# -D__FUZIX__ -DNDEBUG -all: pool_test_gen pool_test_run process_test_gen process_test_run ucp mkfs \ +all: pool_test_gen pool_test_run process_test_gen process_test_run mkfs \ inode_test_gen inode_test_run +#ucp pool_test_gen: pool_test_gen.o ${CC} ${CFLAGS} -o $@ $^ @@ -29,7 +30,8 @@ core.o: core.c core.h pool.h fuzix_fs_or_swap.o: fuzix_fs_or_swap.c fuzix_fs.c swap.h core.h pool.h fuzix_fs.h block_pool.o: block_pool.c block_pool.h -ucp.o: ucp.c fuzix_fs.h +# ucp no longer compiles because many fs routines commented to save space +#ucp.o: ucp.c fuzix_fs.h fuzix_fs.o: fuzix_fs.c fuzix_fs.h util.o: util.c fuzix_fs.h diff --git a/block_pool.c b/block_pool.c index c0a0edb..37031b0 100644 --- a/block_pool.c +++ b/block_pool.c @@ -1,3 +1,4 @@ +#include #include #include #include "block_pool.h" diff --git a/core.c b/core.c index 8fb08da..3b4f3e0 100644 --- a/core.c +++ b/core.c @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/pp.sh b/cpp.sh similarity index 77% rename from pp.sh rename to cpp.sh index 4a7d584..b36dbf0 100755 --- a/pp.sh +++ b/cpp.sh @@ -1,5 +1,7 @@ #!/bin/sh -e -mkdir --parents $1 +dir=$1 +shift +mkdir --parents $dir sed -e 's/^#include a.c - gcc $2 -E a.c |sed -ne "/^END/,/^BEGIN/{s/\"\\(\\/\\/.*\\)\"$/\\1/; s/^BEGIN '\\(#include .*\\)'$/\\1/; p}" |grep -v '^\(BEGIN\|END\)' |./blank.py >$1/$i + gcc "$@" -E a.c |sed -ne "/^END/,/^BEGIN/{s/\"\\(\\/\\/.*\\)\"$/\\1/; s/^BEGIN '\\(#include .*\\)'$/\\1/; p}" |grep -v '^\(BEGIN\|END\)' |./blank.py >$dir/$i done -sed -e 's/^\$/#/' -i *.[ch] $1/*.[ch] -for i in $1/*.h +sed -e 's/^\$/#/' -i *.[ch] $dir/*.[ch] +for i in $dir/*.h do name=`basename $i |sed -e 'y/abcdefghijklmnopqrstuvwxyz\./ABCDEFGHIJKLMNOPQRSTUVWXYZ_/'` ( diff --git a/fuzix_fs.c b/fuzix_fs.c index 35c9ca0..41d8745 100644 --- a/fuzix_fs.c +++ b/fuzix_fs.c @@ -7,12 +7,14 @@ #include "fuzix_fs.h" #include "util.h" +#if 0 struct oft of_tab[OFTSIZE]; /* Open File Table */ +#endif inoptr root; struct cinode i_tab[ITABSIZE]; struct filesys fs_tab[1]; -long long/*uint16_t*/ bufclock; /* Time-stamp counter for LRU */ +long/*uint16_t*/ bufclock; /* Time-stamp counter for LRU */ struct blkbuf bufpool[NBUFS]; struct u_data udata; @@ -44,6 +46,7 @@ void xfs_init(int bootdev) } +#if 0 void xfs_end(void) { register int16_t j; @@ -330,6 +333,7 @@ inoptr rwsetup(int rwflag, int d, char *buf, int nbytes) return (ino); } +#endif uint16_t readi(inoptr ino) { @@ -424,6 +428,7 @@ uint16_t writei(inoptr ino) +#if 0 void updoff(int d) { /* Update current file pointer */ @@ -471,6 +476,7 @@ int fuzix_mknod(char *name, int16_t mode, int16_t dev) i_deref(parent); return (-1); } +#endif void fuzix_sync(void) { @@ -502,6 +508,7 @@ void fuzix_sync(void) bufsync(); /* Clear buffer pool */ } +#if 0 int fuzix_chdir(char *dir) { register inoptr newcwd; @@ -519,12 +526,14 @@ int fuzix_chdir(char *dir) udata.u_cwd = newcwd; return (0); } +#endif int min(int a, int b) { return (a < b ? a : b); } +#if 0 int fuzix_chmod(char *path, int16_t mode) { inoptr ino; @@ -768,6 +777,7 @@ inoptr srch_mt(inoptr ino) return (ino); } +#endif /* I_open is given an inode number and a device number, @@ -856,6 +866,7 @@ badino: +#if 0 /* Ch_link modifies or makes a new entry in the directory for the name * and inode pointer given. The directory is searched for oldname. When * found, it is changed to newname, and it inode # is that of *nindex. @@ -1016,6 +1027,7 @@ nogood: i_deref(pino); return (NULLINODE); } +#endif /* Check the given device number, and return its address in the mount @@ -1228,6 +1240,7 @@ void blk_free(int devno, blkno_t blk) } +#if 0 /* Oft_alloc and oft_deref allocate and dereference (and possibly free) * entries in the open file table. */ @@ -1275,6 +1288,7 @@ int uf_alloc(void) udata.u_error = ENFILE; return (-1); } +#endif /* I_ref increases the reference count of the given inode table entry. @@ -1560,6 +1574,7 @@ void validblk(int dev, blkno_t num) } +#if 0 /* This returns the inode pointer associated with a user's file * descriptor, checking for valid data structures. */ @@ -1602,6 +1617,7 @@ void setftime(inoptr ino, int flag) if (flag & C_TIME) ino->c_node.i_ctime = swizzle32(now); } +#endif int fuzix_getmode(inoptr ino) @@ -1713,7 +1729,7 @@ int bfree(bufptr bp, int dirty) char *tmpbuf(void) { bufptr bp; - bufptr freebuf(); + //bufptr freebuf(); /*printf("Allocating temp block\n");*/ bp = freebuf(); @@ -1728,7 +1744,7 @@ char *tmpbuf(void) char *zerobuf(void) { char *b; - char *tmpbuf(); + //char *tmpbuf(); b = tmpbuf(); bzero(b, 512); diff --git a/fuzix_fs.h b/fuzix_fs.h index e7daa47..7982261 100644 --- a/fuzix_fs.h +++ b/fuzix_fs.h @@ -12,11 +12,11 @@ #define SMOUNTED_WRONGENDIAN 50737 /* byteflipped */ #define CMAGIC 24721 #define UFTSIZE 10 -#define NSIGS 16 +//#define NSIGS 16 #define NDEVS 1 -#define NBUFS 10 +#define NBUFS 4 //10 #define OFTSIZE 15 -#define ITABSIZE 20 +#define ITABSIZE 18 //20 #define _NSIG NSIGS #define NULLINODE ((inoptr)NULL) #define NULLBLK ((blkno_t)-1) @@ -71,7 +71,7 @@ typedef struct blkbuf { blkno_t bf_blk; char bf_dirty; char bf_busy; - long long/*uint16_t*/ bf_time; /* LRU time stamp */ + long/*uint16_t*/ bf_time; /* LRU time stamp */ } blkbuf; typedef blkbuf *bufptr; @@ -176,19 +176,19 @@ typedef struct filesys { #ifdef UCP typedef struct u_data { - struct p_tab *u_ptab; /* Process table pointer */ + //struct p_tab *u_ptab; /* Process table pointer */ char u_insys; /* True if in kernel */ - char u_callno; /* sys call being executed. */ - char *u_retloc; /* Return location from sys call */ - int u_retval; /* Return value from sys call */ + //char u_callno; /* sys call being executed. */ + //char *u_retloc; /* Return location from sys call */ + //int u_retval; /* Return value from sys call */ int u_error; /* Last error number */ - char *u_sp; /* Used when a process is swapped. */ - char *u_bc; /* Place to save user's frame pointer */ - int u_cursig; /* Signal currently being caught */ - int u_argn; /* Last system call arg */ - int u_argn1; /* This way because args on stack backwards */ - int u_argn2; - int u_argn3; /* args n-3, n-2, n-1, and n */ + //char *u_sp; /* Used when a process is swapped. */ + //char *u_bc; /* Place to save user's frame pointer */ + //int u_cursig; /* Signal currently being caught */ + //int u_argn; /* Last system call arg */ + //int u_argn1; /* This way because args on stack backwards */ + //int u_argn2; + //int u_argn3; /* args n-3, n-2, n-1, and n */ char * u_base; /* Source or dest for I/O */ unsigned u_count; /* Amount for I/O */ @@ -196,26 +196,27 @@ typedef struct u_data { struct blkbuf *u_buf; char u_sysio; /* True if I/O is to system data space 280*/ - int u_gid; + //int u_gid; int u_euid; int u_egid; int u_mask; /* umask: file creation mode mask */ - uint32_t u_time; /* Start time */ + //uint32_t u_time; /* Start time */ char u_files[UFTSIZE]; /* Process file table: contains indexes into open file table. */ inoptr u_cwd; /* Index into inode table of cwd. */ - unsigned u_break; /* Top of data space */ - inoptr u_ino; /* Used during execve() */ - char *u_isp; /* Value of initial sp (argv) */ - - int (*u_sigvec[NSIGS])(); /* Array of signal vectors */ - char u_name[8]; /* Name invoked with */ - uint32_t u_utime; /* Elapsed ticks in user mode */ - uint32_t u_stime; /* Ticks in system mode */ - uint32_t u_cutime; /* Total childrens ticks */ - uint32_t u_cstime; + //unsigned u_break; /* Top of data space */ + //inoptr u_ino; /* Used during execve() */ + //char *u_isp; /* Value of initial sp (argv) */ + + //int (*u_sigvec[NSIGS])(); /* Array of signal vectors */ + //char u_name[8]; /* Name invoked with */ + //uint32_t u_utime; /* Elapsed ticks in user mode */ + //uint32_t u_stime; /* Ticks in system mode */ + //uint32_t u_cutime; /* Total childrens ticks */ + //uint32_t u_cstime; } u_data; +#if 0 typedef struct oft { uint32_t o_ptr; /* File position pointer */ inoptr o_inode; /* Pointer into in-core inode table */ @@ -223,11 +224,12 @@ typedef struct oft { char o_refs; /* Reference count: depends on # of active children*/ } oft; extern struct oft of_tab[OFTSIZE]; /* Open File Table */ +#endif extern inoptr root; extern struct cinode i_tab[ITABSIZE]; extern struct filesys fs_tab[1]; -extern long long/*uint16_t*/ bufclock; /* Time-stamp counter for LRU */ +extern long/*uint16_t*/ bufclock; /* Time-stamp counter for LRU */ extern struct blkbuf bufpool[NBUFS]; extern struct u_data udata; diff --git a/gen.sh b/gen.sh index 2023a40..ca5fc90 100755 --- a/gen.sh +++ b/gen.sh @@ -3,6 +3,9 @@ # call with -DNDEBUG to generate a release build of the expanded source # (note that we cannot preserve #ifndef NDEBUG type constructs in output) +# call with -D__FUZIX__ -DNDEBUG to generate a fuzix build (smaller block +# sizes, and simplified hash function that doesn't use "long long" type) + sed -e 's/^#define MOVEABLE_POOL 1/\/\/#define MOVEABLE_POOL 1/' -i pool.c # we will only use non-moveable swap, so it must be preallocated, @@ -16,15 +19,15 @@ sed -e 's/^#define MOVEABLE_CORE 1/\/\/#define MOVEABLE_CORE 1/' -i core.h sed -e 's/^#define INODE_SWAP 1/\/\/#define INODE_SWAP 1/' -i process.h sed -e 's/^#define INDIRECT_SWAP 1/\/\/#define INDIRECT_SWAP 1/' -i swap.h -./pp.sh indirect_core_preallocate_swap $1 +./cpp.sh indirect_core_preallocate_swap "$@" cp rassert.h indirect_core_preallocate_swap sed -e 's/^\/\/#define INDIRECT_SWAP 1/#define INDIRECT_SWAP 1/' -i swap.h -./pp.sh indirect_core_indirect_swap $1 +./cpp.sh indirect_core_indirect_swap "$@" cp rassert.h indirect_core_indirect_swap sed -e 's/^\/\/#define INODE_SWAP 1/#define INODE_SWAP 1/' -i process.h -./pp.sh indirect_core_inode_swap $1 +./cpp.sh indirect_core_inode_swap "$@" rm indirect_core_inode_swap/swap.[ch] cp rassert.h fuzix_fs.[ch] util.[ch] indirect_core_inode_swap @@ -36,15 +39,17 @@ sed -e 's/^\/\/#define MOVEABLE_CORE 1/#define MOVEABLE_CORE 1/' -i core.h sed -e 's/^#define INODE_SWAP 1/\/\/#define INODE_SWAP 1/' -i process.h sed -e 's/^#define INDIRECT_SWAP 1/\/\/#define INDIRECT_SWAP 1/' -i swap.h -./pp.sh moveable_core_preallocate_swap $1 +./cpp.sh moveable_core_preallocate_swap "$@" rm moveable_core_preallocate_swap/block_pool.[ch] cp rassert.h moveable_core_preallocate_swap sed -e 's/^\/\/#define INDIRECT_SWAP 1/#define INDIRECT_SWAP 1/' -i swap.h -./pp.sh moveable_core_indirect_swap $1 +./cpp.sh moveable_core_indirect_swap "$@" cp rassert.h moveable_core_indirect_swap sed -e 's/^\/\/#define INODE_SWAP 1/#define INODE_SWAP 1/' -i process.h -./pp.sh moveable_core_inode_swap $1 +./cpp.sh moveable_core_inode_swap "$@" rm moveable_core_inode_swap/block_pool.[ch] moveable_core_inode_swap/swap.[ch] cp rassert.h fuzix_fs.[ch] util.[ch] moveable_core_inode_swap + +sed -e 's/^#define INODE_SWAP 1/\/\/#define INODE_SWAP 1/' -i process.h diff --git a/pool_test_run.c b/pool_test_run.c index 85cda5c..2d7a575 100644 --- a/pool_test_run.c +++ b/pool_test_run.c @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/process.c b/process.c index 6d7a0c5..7befffc 100644 --- a/process.c +++ b/process.c @@ -1,3 +1,4 @@ +#include #include // temporary #include #ifndef NDEBUG @@ -57,11 +58,11 @@ static long estimate_size(long size) { // basically the inverse of the above, estimates size of files that could be // created if space is divided into at most n files, but a bit conservatively -static long estimate_free(/*int n*/) { +static long estimate_free(void) {/*int n) {*/ int blocks; // at most one partial indirect and double indirect block per file - blocks = fs_tab[0].s_tfree - 2/*(n << 1)*/; + blocks = fs_tab[0].s_tfree - 2;/*(n << 1);*/ // max number of FULL indirect blocks (ignore the 18 direct blocks) blocks -= blocks / (DISK_INDIRECT_SIZE + 1); return (long)blocks << DISK_BLOCK_SHIFT; @@ -341,7 +342,7 @@ static bool do_swap_out(int swap_out) { //printf(" %d", swap_block); #endif #endif - putchar('*'); + //putchar('*'); core_to_swap_copy( (long)core_block << BLOCK_SHIFT, (long)swap_block << BLOCK_SHIFT, diff --git a/process.h b/process.h index d63a317..2bdd0c2 100644 --- a/process.h +++ b/process.h @@ -1,10 +1,15 @@ #ifndef _PROCESS_H #define _PROCESS_H 1 +#ifdef __FUZIX__ +#define BLOCK_SIZE 0x10 +#define BLOCK_SHIFT 4 +#else #define BLOCK_SIZE 0x1000 #define BLOCK_SHIFT 12 +#endif -#define INODE_SWAP 1 +//#define INODE_SWAP 1 #ifdef INODE_SWAP #define DISK_BLOCK_SIZE 0x200 #define DISK_BLOCK_SHIFT 9 diff --git a/process_test_gen.c b/process_test_gen.c index 6dbf00f..14d17a5 100644 --- a/process_test_gen.c +++ b/process_test_gen.c @@ -4,8 +4,13 @@ #include #include "rassert.h" +#ifdef __FUZIX__ +#define BLOCK_SIZE 0x10 +#define BLOCK_SHIFT 4 +#else #define BLOCK_SIZE 0x1000 #define BLOCK_SHIFT 12 +#endif int rand_int(int n) { return (int)((long long)rand() * n / (RAND_MAX + 1LL)); diff --git a/process_test_run.c b/process_test_run.c index 7f41cb5..712a44a 100644 --- a/process_test_run.c +++ b/process_test_run.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -14,7 +15,11 @@ #include "swap.h" #endif +#ifdef __FUZIX__ +#define TRANSFER_SIZE 0x400 +#else #define TRANSFER_SIZE 0x8000 +#endif uint8_t *core_block_mem; #ifndef INODE_SWAP @@ -23,7 +28,11 @@ uint8_t *swap_block_mem; void core_hash_init(int process, long base, long size, long offset) { long i, addr; +#ifdef __FUZIX__ + int hash; +#else long long hash; +#endif //printf("core_hash_init %d %ld(%d) %ld(%d) %ld(%d)\n", process, base, (int)(base >> BLOCK_SHIFT), size, (int)((size + (BLOCK_SIZE - 1)) >> BLOCK_SHIFT), offset, (int)(offset >> BLOCK_SHIFT)); for (i = 0L; i < size; ++i) { @@ -33,11 +42,15 @@ void core_hash_init(int process, long base, long size, long offset) { (core_table_mem[addr >> BLOCK_SHIFT] << BLOCK_SHIFT) | (addr & (BLOCK_SIZE - 1)); #endif +#ifdef __FUZIX__ + hash = process * 17 + ((int)i + (int)offset) * 29; +#else hash = process * 17 + (i + offset) * 29; hash = (hash & 0xffffffffLL) + (hash >> 32); hash = (hash & 0xffffLL) + (hash >> 16); hash = (hash & 0xffLL) + (hash >> 8); hash = (hash & 0xffLL) + (hash >> 8); +#endif rassert(core_block_mem[addr] == 0xaa); core_block_mem[addr] = (uint8_t)hash; } @@ -45,7 +58,11 @@ void core_hash_init(int process, long base, long size, long offset) { void core_hash_verify(int process, long base, long size, long offset) { long i, addr; +#ifdef __FUZIX__ + int hash; +#else long long hash; +#endif //printf("core_hash_verify %d %ld(%d) %ld(%d) %ld(%d)\n", process, base, (int)(base >> BLOCK_SHIFT), size, (int)((size + (BLOCK_SIZE - 1)) >> BLOCK_SHIFT), offset, (int)(offset >> BLOCK_SHIFT)); for (i = 0L; i < size; ++i) { @@ -55,11 +72,15 @@ void core_hash_verify(int process, long base, long size, long offset) { (core_table_mem[addr >> BLOCK_SHIFT] << BLOCK_SHIFT) | (addr & (BLOCK_SIZE - 1)); #endif +#ifdef __FUZIX__ + hash = process * 17 + ((int)i + (int)offset) * 29; +#else hash = process * 17 + (i + offset) * 29; hash = (hash & 0xffffffffLL) + (hash >> 32); hash = (hash & 0xffffLL) + (hash >> 16); hash = (hash & 0xffLL) + (hash >> 8); hash = (hash & 0xffLL) + (hash >> 8); +#endif rassert(core_block_mem[addr] == (uint8_t)hash); core_block_mem[addr] = 0xaa; } @@ -69,8 +90,12 @@ void core_hash_verify(int process, long base, long size, long offset) { void swap_hash_verify(int process, struct cinode *inode) { long offset, count; uint8_t buf[TRANSFER_SIZE]; - int i; + long i; +#ifdef __FUZIX__ + int hash; +#else long long hash; +#endif for ( offset = 0; @@ -87,11 +112,15 @@ void swap_hash_verify(int process, struct cinode *inode) { rassert(readi(inode) == count && udata.u_error == 0); for (i = 0; i < count; ++i) { +#ifdef __FUZIX__ + hash = process * 17 + ((int)i + (int)offset) * 29; +#else hash = process * 17 + (i + offset) * 29; hash = (hash & 0xffffffffLL) + (hash >> 32); hash = (hash & 0xffffLL) + (hash >> 16); hash = (hash & 0xffLL) + (hash >> 8); hash = (hash & 0xffLL) + (hash >> 8); +#endif rassert(buf[i] == (uint8_t)hash); } } @@ -99,7 +128,11 @@ void swap_hash_verify(int process, struct cinode *inode) { #else void swap_hash_verify(int process, long base, long size) { long i, addr; +#ifdef __FUZIX__ + int hash; +#else long long hash; +#endif //printf("swap_hash_verify %d %ld(%d) %ld(%d)\n", process, base, (int)(base >> BLOCK_SHIFT), size, (int)((size + (BLOCK_SIZE - 1)) >> BLOCK_SHIFT)); for (i = 0L; i < size; ++i) { @@ -109,11 +142,15 @@ void swap_hash_verify(int process, long base, long size) { (swap_table_mem[addr >> BLOCK_SHIFT] << BLOCK_SHIFT) | (addr & (BLOCK_SIZE - 1)); #endif +#ifdef __FUZIX__ + hash = process * 17 + (int)i * 29; +#else hash = process * 17 + i * 29; hash = (hash & 0xffffffffLL) + (hash >> 32); hash = (hash & 0xffffLL) + (hash >> 16); hash = (hash & 0xffLL) + (hash >> 8); hash = (hash & 0xffLL) + (hash >> 8); +#endif rassert(swap_block_mem[addr] == (uint8_t)hash); swap_block_mem[addr] = 0xaa; } @@ -333,7 +370,7 @@ int main(int argc, char **argv) { while (true) { //printf("avail %d %d(%d) %d(%d)\n", process_avail, CORE_AVAIL, core_table.avail, SWAP_AVAIL, swap_table.avail); - switch (scanf("%s", buf)) { + switch ((unsigned int)scanf("%s", buf)) { // cast because of ACK bug case -1: goto done; case 1: diff --git a/rassert.h b/rassert.h index 552f04b..f9de3da 100644 --- a/rassert.h +++ b/rassert.h @@ -1,19 +1,32 @@ #ifndef _RASSERT_H #define _RASSERT_H 1 -#include +// tries to be the same as assert(), but always present even with NDEBUG + +#ifdef __FUZIX__ +extern void __assert(const char *__expr, const char *__file, const int __line); -/* This prints an "Assertion failed" message and aborts. */ +#if 1 // smaller code +#define rassert(expr) \ + ((void) ((expr) || (__assert ("", __FILE__, __LINE__), 0))) +#else +#define rassert(expr) \ + ((void) ((expr) || (__assert (__STRING(expr), __FILE__, __LINE__), 0))) +#endif +#elif defined(__GLIBC__) extern void __assert_fail (const char *__assertion, const char *__file, unsigned int __line, const char *__function) __THROW __attribute__ ((__noreturn__)); -# define rassert(expr) \ - ((void) sizeof ((expr) ? 1 : 0), __extension__ ({ \ - if (expr) \ - ; /* empty */ \ - else \ - __assert_fail (#expr, __FILE__, __LINE__, __func__); \ - })) +# define rassert(expr) \ + ((expr) \ + ? (void) (0) \ + : __assert_fail (#expr, __FILE__, __LINE__, __extension__ __PRETTY_FUNCTION__)) +#else +// for unsupported platforms, it won't work with NDEBUG +#include + +#define rassert(expr) assert(expr) +#endif #endif diff --git a/swap.c b/swap.c index 33a411b..58e5979 100644 --- a/swap.c +++ b/swap.c @@ -1,3 +1,4 @@ +#include #include #include #include -- 2.34.1