diff --git a/work/tp2/pipebis.c b/work/tp2/pipebis.c
index 43e97c4b49f356faa1ef3d0c9b5fa2e8d33ff438..2efe4d15be0db99aa83298d1ef3982e3d30937bc 100644
--- a/work/tp2/pipebis.c
+++ b/work/tp2/pipebis.c
@@ -176,7 +176,8 @@ static int device_release(struct inode *inode, struct file *file)
 /* Called when a process, which already opened the dev file, attempts to 
  * read from it. 
  */ 
-static int last_writen_bytes;
+static int last_writen_bytes = 0;
+static int last_read_bytes = 0;
 static ssize_t device_read(struct file *filp, /* see include/linux/fs.h   */ 
                            char __user *buffer, /* buffer to fill with data */ 
                            size_t length, /* length of the buffer     */ 
@@ -188,8 +189,8 @@ static ssize_t device_read(struct file *filp, /* see include/linux/fs.h   */
  
     /* Actually put the data into the buffer */ 
     while (asee_buf_count > 0) { 
-        if (last_writen_bytes >= asee_buf_size) {
-            last_writen_bytes = 0;
+        if (last_read_bytes >= asee_buf_size) {
+            last_read_bytes = 0;
         }
         /* The buffer is in the user data segment, not the kernel 
          * segment so "*" assignment won't work.  We have to use 
@@ -197,15 +198,14 @@ static ssize_t device_read(struct file *filp, /* see include/linux/fs.h   */
          * the user data segment. 
          */ 
         
-        put_user(*(msg_ptr + last_writen_bytes), buffer++);
+        put_user(*(msg_ptr + last_read_bytes), buffer++);
         // Try to clear the read
-        *(msg_ptr + last_writen_bytes) = '\0';
-        last_writen_bytes++;
+        *(msg_ptr + last_read_bytes) = '\0';
+        last_read_bytes++;
         asee_buf_count--;
         bytes_read++;
     } 
- 
-    *offset = last_writen_bytes; 
+    *offset = last_read_bytes; 
  
     /* Most read functions return the number of bytes put into the buffer. */ 
     return bytes_read; 
@@ -226,8 +226,11 @@ static ssize_t device_write(struct file *filp, const char __user *buff,
         get_user(*(msg + current_bytes), buff + cpt);
         current_bytes++;
         bytes_writen++;
-        asee_buf_count++;
+        if (asee_buf_count < asee_buf_size) {
+            asee_buf_count++;
+        }
     }
+    last_read_bytes = (last_read_bytes + bytes_writen) % asee_buf_count;
 
     last_writen_bytes = current_bytes;
     *off = last_writen_bytes; 
@@ -238,4 +241,4 @@ static ssize_t device_write(struct file *filp, const char __user *buff,
 module_init(pipebis_init); 
 module_exit(pipebis_exit); 
  
-MODULE_LICENSE("GPL");
\ No newline at end of file
+MODULE_LICENSE("GPL");
diff --git a/work/tp3/Makefile b/work/tp3/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..6ed65a4e99ccb40b0d7e3b2259561f863ee028a0
--- /dev/null
+++ b/work/tp3/Makefile
@@ -0,0 +1,9 @@
+KDIR=../../build/kvm/
+
+obj-m += sleep.o example_mutex.o example_spinlock.o example_rwlock.o example_atomic.o pipebis3.o
+PWD := $(CURDIR) 
+
+all: 
+	make -C $(KDIR) M=$(PWD) modules 
+clean: 
+	make -C $(KDIR) M=$(PWD) clean
diff --git a/work/tp3/cat_nonblock b/work/tp3/cat_nonblock
new file mode 100755
index 0000000000000000000000000000000000000000..89aa7580ea438fcd73a69d1d97bdf390a3aa7a30
Binary files /dev/null and b/work/tp3/cat_nonblock differ
diff --git a/work/tp3/cat_nonblock.c b/work/tp3/cat_nonblock.c
new file mode 100644
index 0000000000000000000000000000000000000000..017418282d819a0d4116da6fed5e7aced0f1d92a
--- /dev/null
+++ b/work/tp3/cat_nonblock.c
@@ -0,0 +1,59 @@
+/* 
+ *  cat_nonblock.c - open a file and display its contents, but exit rather than 
+ *  wait for input. 
+ */ 
+#include <errno.h> /* for errno */ 
+#include <fcntl.h> /* for open */ 
+#include <stdio.h> /* standard I/O */ 
+#include <stdlib.h> /* for exit */ 
+#include <unistd.h> /* for read */ 
+ 
+#define MAX_BYTES 1024 * 4 
+ 
+int main(int argc, char *argv[]) 
+{ 
+    int fd; /* The file descriptor for the file to read */ 
+    size_t bytes; /* The number of bytes read */ 
+    char buffer[MAX_BYTES]; /* The buffer for the bytes */ 
+ 
+    /* Usage */ 
+    if (argc != 2) { 
+        printf("Usage: %s <filename>\n", argv[0]); 
+        puts("Reads the content of a file, but doesn't wait for input"); 
+        exit(-1); 
+    } 
+ 
+    /* Open the file for reading in non blocking mode */ 
+    fd = open(argv[1], O_RDONLY | O_NONBLOCK); 
+ 
+    /* If open failed */ 
+    if (fd == -1) { 
+        puts(errno == EAGAIN ? "Open would block" : "Open failed"); 
+        exit(-1); 
+    } 
+ 
+    /* Read the file and output its contents */ 
+    do { 
+        /* Read characters from the file */ 
+        bytes = read(fd, buffer, MAX_BYTES); 
+ 
+        /* If there's an error, report it and die */ 
+        if (bytes == -1) { 
+            if (errno == EAGAIN) 
+                puts("Normally I'd block, but you told me not to"); 
+            else 
+                puts("Another read error"); 
+            exit(-1); 
+        } 
+ 
+        /* Print the characters */ 
+        if (bytes > 0) { 
+            for (int i = 0; i < bytes; i++) 
+                putchar(buffer[i]); 
+        } 
+ 
+        /* While there are no errors and the file isn't over */ 
+    } while (bytes > 0); 
+ 
+    return 0; 
+}
\ No newline at end of file
diff --git a/work/tp3/example_atomic.c b/work/tp3/example_atomic.c
new file mode 100644
index 0000000000000000000000000000000000000000..19a1e8e4c4341e2b383401fa519ff90cf6226ff5
--- /dev/null
+++ b/work/tp3/example_atomic.c
@@ -0,0 +1,75 @@
+/* 
+ * example_atomic.c 
+ */ 
+#include <linux/atomic.h> 
+#include <linux/bitops.h> 
+#include <linux/module.h> 
+#include <linux/printk.h> 
+ 
+#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c" 
+#define BYTE_TO_BINARY(byte)                                                   \ 
+    ((byte & 0x80) ? '1' : '0'), ((byte & 0x40) ? '1' : '0'),                  \ 
+        ((byte & 0x20) ? '1' : '0'), ((byte & 0x10) ? '1' : '0'),              \ 
+        ((byte & 0x08) ? '1' : '0'), ((byte & 0x04) ? '1' : '0'),              \ 
+        ((byte & 0x02) ? '1' : '0'), ((byte & 0x01) ? '1' : '0') 
+ 
+static void atomic_add_subtract(void) 
+{ 
+    atomic_t debbie; 
+    atomic_t chris = ATOMIC_INIT(50); 
+ 
+    atomic_set(&debbie, 45); 
+ 
+    /* subtract one */ 
+    atomic_dec(&debbie); 
+ 
+    atomic_add(7, &debbie); 
+ 
+    /* add one */ 
+    atomic_inc(&debbie); 
+ 
+    pr_info("chris: %d, debbie: %d\n", atomic_read(&chris), 
+            atomic_read(&debbie)); 
+} 
+ 
+static void atomic_bitwise(void) 
+{ 
+    unsigned long word = 0; 
+ 
+    pr_info("Bits 0: " BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(word)); 
+    set_bit(3, &word); 
+    set_bit(5, &word); 
+    pr_info("Bits 1: " BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(word)); 
+    clear_bit(5, &word); 
+    pr_info("Bits 2: " BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(word)); 
+    change_bit(3, &word); 
+ 
+    pr_info("Bits 3: " BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(word)); 
+    if (test_and_set_bit(3, &word)) 
+        pr_info("wrong\n"); 
+    pr_info("Bits 4: " BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(word)); 
+ 
+    word = 255; 
+    pr_info("Bits 5: " BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(word)); 
+} 
+ 
+static int __init example_atomic_init(void) 
+{ 
+    pr_info("example_atomic started\n"); 
+ 
+    atomic_add_subtract(); 
+    atomic_bitwise(); 
+ 
+    return 0; 
+} 
+ 
+static void __exit example_atomic_exit(void) 
+{ 
+    pr_info("example_atomic exit\n"); 
+} 
+ 
+module_init(example_atomic_init); 
+module_exit(example_atomic_exit); 
+ 
+MODULE_DESCRIPTION("Atomic operations example"); 
+MODULE_LICENSE("GPL");
\ No newline at end of file
diff --git a/work/tp3/example_atomic.mod.c b/work/tp3/example_atomic.mod.c
new file mode 100644
index 0000000000000000000000000000000000000000..ec0a3ffa9fa289fdf2ed69f86e76d1e7f9b8556a
--- /dev/null
+++ b/work/tp3/example_atomic.mod.c
@@ -0,0 +1,48 @@
+#include <linux/module.h>
+#define INCLUDE_VERMAGIC
+#include <linux/build-salt.h>
+#include <linux/elfnote-lto.h>
+#include <linux/export-internal.h>
+#include <linux/vermagic.h>
+#include <linux/compiler.h>
+
+#ifdef CONFIG_UNWINDER_ORC
+#include <asm/orc_header.h>
+ORC_HEADER;
+#endif
+
+BUILD_SALT;
+BUILD_LTO_INFO;
+
+MODULE_INFO(vermagic, VERMAGIC_STRING);
+MODULE_INFO(name, KBUILD_MODNAME);
+
+__visible struct module __this_module
+__section(".gnu.linkonce.this_module") = {
+	.name = KBUILD_MODNAME,
+	.init = init_module,
+#ifdef CONFIG_MODULE_UNLOAD
+	.exit = cleanup_module,
+#endif
+	.arch = MODULE_ARCH_INIT,
+};
+
+#ifdef CONFIG_RETPOLINE
+MODULE_INFO(retpoline, "Y");
+#endif
+
+
+
+static const struct modversion_info ____versions[]
+__used __section("__versions") = {
+	{ 0x5b8239ca, "__x86_return_thunk" },
+	{ 0xf0fdf6cb, "__stack_chk_fail" },
+	{ 0xbdfb6dbb, "__fentry__" },
+	{ 0x122c3a7e, "_printk" },
+	{ 0x76800044, "module_layout" },
+};
+
+MODULE_INFO(depends, "");
+
+
+MODULE_INFO(srcversion, "AEE2A7B8CBD828FC0381EA8");
diff --git a/work/tp3/example_mutex.c b/work/tp3/example_mutex.c
new file mode 100644
index 0000000000000000000000000000000000000000..1504a5fb7b65bd572be3ab454dea1e4d7d3b32c0
--- /dev/null
+++ b/work/tp3/example_mutex.c
@@ -0,0 +1,40 @@
+/* 
+ * example_mutex.c 
+ */ 
+#include <linux/module.h> 
+#include <linux/mutex.h> 
+#include <linux/printk.h> 
+ 
+static DEFINE_MUTEX(mymutex); 
+ 
+static int __init example_mutex_init(void) 
+{ 
+    int ret; 
+ 
+    pr_info("example_mutex init\n"); 
+ 
+    ret = mutex_trylock(&mymutex); 
+    if (ret != 0) { 
+        pr_info("mutex is locked\n"); 
+ 
+        if (mutex_is_locked(&mymutex) == 0) 
+            pr_info("The mutex failed to lock!\n"); 
+ 
+        mutex_unlock(&mymutex); 
+        pr_info("mutex is unlocked\n"); 
+    } else 
+        pr_info("Failed to lock\n"); 
+ 
+    return 0; 
+} 
+ 
+static void __exit example_mutex_exit(void) 
+{ 
+    pr_info("example_mutex exit\n"); 
+} 
+ 
+module_init(example_mutex_init); 
+module_exit(example_mutex_exit); 
+ 
+MODULE_DESCRIPTION("Mutex example"); 
+MODULE_LICENSE("GPL");
\ No newline at end of file
diff --git a/work/tp3/example_mutex.mod.c b/work/tp3/example_mutex.mod.c
new file mode 100644
index 0000000000000000000000000000000000000000..f6d2b4a89b2e3b15498f77e4f00adc6d48d85830
--- /dev/null
+++ b/work/tp3/example_mutex.mod.c
@@ -0,0 +1,50 @@
+#include <linux/module.h>
+#define INCLUDE_VERMAGIC
+#include <linux/build-salt.h>
+#include <linux/elfnote-lto.h>
+#include <linux/export-internal.h>
+#include <linux/vermagic.h>
+#include <linux/compiler.h>
+
+#ifdef CONFIG_UNWINDER_ORC
+#include <asm/orc_header.h>
+ORC_HEADER;
+#endif
+
+BUILD_SALT;
+BUILD_LTO_INFO;
+
+MODULE_INFO(vermagic, VERMAGIC_STRING);
+MODULE_INFO(name, KBUILD_MODNAME);
+
+__visible struct module __this_module
+__section(".gnu.linkonce.this_module") = {
+	.name = KBUILD_MODNAME,
+	.init = init_module,
+#ifdef CONFIG_MODULE_UNLOAD
+	.exit = cleanup_module,
+#endif
+	.arch = MODULE_ARCH_INIT,
+};
+
+#ifdef CONFIG_RETPOLINE
+MODULE_INFO(retpoline, "Y");
+#endif
+
+
+
+static const struct modversion_info ____versions[]
+__used __section("__versions") = {
+	{ 0xbdfb6dbb, "__fentry__" },
+	{ 0xbb9ed3bf, "mutex_trylock" },
+	{ 0x364c23ad, "mutex_is_locked" },
+	{ 0x3213f038, "mutex_unlock" },
+	{ 0x122c3a7e, "_printk" },
+	{ 0x5b8239ca, "__x86_return_thunk" },
+	{ 0x76800044, "module_layout" },
+};
+
+MODULE_INFO(depends, "");
+
+
+MODULE_INFO(srcversion, "DFB03C104EE786ED530AED0");
diff --git a/work/tp3/example_rwlock.c b/work/tp3/example_rwlock.c
new file mode 100644
index 0000000000000000000000000000000000000000..002a655eedee8b1226c79e4ca87ab626b45975b4
--- /dev/null
+++ b/work/tp3/example_rwlock.c
@@ -0,0 +1,55 @@
+/* 
+ * example_rwlock.c 
+ */ 
+#include <linux/module.h> 
+#include <linux/printk.h> 
+#include <linux/rwlock.h> 
+ 
+static DEFINE_RWLOCK(myrwlock); 
+ 
+static void example_read_lock(void) 
+{ 
+    unsigned long flags; 
+ 
+    read_lock_irqsave(&myrwlock, flags); 
+    pr_info("Read Locked\n"); 
+ 
+    /* Read from something */ 
+ 
+    read_unlock_irqrestore(&myrwlock, flags); 
+    pr_info("Read Unlocked\n"); 
+} 
+ 
+static void example_write_lock(void) 
+{ 
+    unsigned long flags; 
+ 
+    write_lock_irqsave(&myrwlock, flags); 
+    pr_info("Write Locked\n"); 
+ 
+    /* Write to something */ 
+ 
+    write_unlock_irqrestore(&myrwlock, flags); 
+    pr_info("Write Unlocked\n"); 
+} 
+ 
+static int __init example_rwlock_init(void) 
+{ 
+    pr_info("example_rwlock started\n"); 
+ 
+    example_read_lock(); 
+    example_write_lock(); 
+ 
+    return 0; 
+} 
+ 
+static void __exit example_rwlock_exit(void) 
+{ 
+    pr_info("example_rwlock exit\n"); 
+} 
+ 
+module_init(example_rwlock_init); 
+module_exit(example_rwlock_exit); 
+ 
+MODULE_DESCRIPTION("Read/Write locks example"); 
+MODULE_LICENSE("GPL");
\ No newline at end of file
diff --git a/work/tp3/example_rwlock.mod.c b/work/tp3/example_rwlock.mod.c
new file mode 100644
index 0000000000000000000000000000000000000000..b0003317d9c6eb19def25f79343733523ab04d97
--- /dev/null
+++ b/work/tp3/example_rwlock.mod.c
@@ -0,0 +1,51 @@
+#include <linux/module.h>
+#define INCLUDE_VERMAGIC
+#include <linux/build-salt.h>
+#include <linux/elfnote-lto.h>
+#include <linux/export-internal.h>
+#include <linux/vermagic.h>
+#include <linux/compiler.h>
+
+#ifdef CONFIG_UNWINDER_ORC
+#include <asm/orc_header.h>
+ORC_HEADER;
+#endif
+
+BUILD_SALT;
+BUILD_LTO_INFO;
+
+MODULE_INFO(vermagic, VERMAGIC_STRING);
+MODULE_INFO(name, KBUILD_MODNAME);
+
+__visible struct module __this_module
+__section(".gnu.linkonce.this_module") = {
+	.name = KBUILD_MODNAME,
+	.init = init_module,
+#ifdef CONFIG_MODULE_UNLOAD
+	.exit = cleanup_module,
+#endif
+	.arch = MODULE_ARCH_INIT,
+};
+
+#ifdef CONFIG_RETPOLINE
+MODULE_INFO(retpoline, "Y");
+#endif
+
+
+
+static const struct modversion_info ____versions[]
+__used __section("__versions") = {
+	{ 0xb1342cdb, "_raw_read_lock_irqsave" },
+	{ 0xdf2ebb87, "_raw_read_unlock_irqrestore" },
+	{ 0x5021bd81, "_raw_write_lock_irqsave" },
+	{ 0xeb078aee, "_raw_write_unlock_irqrestore" },
+	{ 0x5b8239ca, "__x86_return_thunk" },
+	{ 0xbdfb6dbb, "__fentry__" },
+	{ 0x122c3a7e, "_printk" },
+	{ 0x76800044, "module_layout" },
+};
+
+MODULE_INFO(depends, "");
+
+
+MODULE_INFO(srcversion, "D9918670193AA1C346E918B");
diff --git a/work/tp3/example_spinlock.c b/work/tp3/example_spinlock.c
new file mode 100644
index 0000000000000000000000000000000000000000..9850a6470b2bb2c902486c0cfbd59090cfd84b24
--- /dev/null
+++ b/work/tp3/example_spinlock.c
@@ -0,0 +1,62 @@
+/* 
+ * example_spinlock.c 
+ */ 
+#include <linux/init.h> 
+#include <linux/module.h> 
+#include <linux/printk.h> 
+#include <linux/spinlock.h> 
+ 
+static DEFINE_SPINLOCK(sl_static); 
+static spinlock_t sl_dynamic; 
+ 
+static void example_spinlock_static(void) 
+{ 
+    unsigned long flags; 
+ 
+    spin_lock_irqsave(&sl_static, flags); 
+    pr_info("Locked static spinlock\n"); 
+ 
+    /* Do something or other safely. Because this uses 100% CPU time, this 
+     * code should take no more than a few milliseconds to run. 
+     */ 
+ 
+    spin_unlock_irqrestore(&sl_static, flags); 
+    pr_info("Unlocked static spinlock\n"); 
+} 
+ 
+static void example_spinlock_dynamic(void) 
+{ 
+    unsigned long flags; 
+ 
+    spin_lock_init(&sl_dynamic); 
+    spin_lock_irqsave(&sl_dynamic, flags); 
+    pr_info("Locked dynamic spinlock\n"); 
+ 
+    /* Do something or other safely. Because this uses 100% CPU time, this 
+     * code should take no more than a few milliseconds to run. 
+     */ 
+ 
+    spin_unlock_irqrestore(&sl_dynamic, flags); 
+    pr_info("Unlocked dynamic spinlock\n"); 
+} 
+ 
+static int __init example_spinlock_init(void) 
+{ 
+    pr_info("example spinlock started\n"); 
+ 
+    example_spinlock_static(); 
+    example_spinlock_dynamic(); 
+ 
+    return 0; 
+} 
+ 
+static void __exit example_spinlock_exit(void) 
+{ 
+    pr_info("example spinlock exit\n"); 
+} 
+ 
+module_init(example_spinlock_init); 
+module_exit(example_spinlock_exit); 
+ 
+MODULE_DESCRIPTION("Spinlock example"); 
+MODULE_LICENSE("GPL");
\ No newline at end of file
diff --git a/work/tp3/example_spinlock.mod.c b/work/tp3/example_spinlock.mod.c
new file mode 100644
index 0000000000000000000000000000000000000000..27d03f182aacb6c68d29b6b58c92b952f9a60f99
--- /dev/null
+++ b/work/tp3/example_spinlock.mod.c
@@ -0,0 +1,49 @@
+#include <linux/module.h>
+#define INCLUDE_VERMAGIC
+#include <linux/build-salt.h>
+#include <linux/elfnote-lto.h>
+#include <linux/export-internal.h>
+#include <linux/vermagic.h>
+#include <linux/compiler.h>
+
+#ifdef CONFIG_UNWINDER_ORC
+#include <asm/orc_header.h>
+ORC_HEADER;
+#endif
+
+BUILD_SALT;
+BUILD_LTO_INFO;
+
+MODULE_INFO(vermagic, VERMAGIC_STRING);
+MODULE_INFO(name, KBUILD_MODNAME);
+
+__visible struct module __this_module
+__section(".gnu.linkonce.this_module") = {
+	.name = KBUILD_MODNAME,
+	.init = init_module,
+#ifdef CONFIG_MODULE_UNLOAD
+	.exit = cleanup_module,
+#endif
+	.arch = MODULE_ARCH_INIT,
+};
+
+#ifdef CONFIG_RETPOLINE
+MODULE_INFO(retpoline, "Y");
+#endif
+
+
+
+static const struct modversion_info ____versions[]
+__used __section("__versions") = {
+	{ 0x34db050b, "_raw_spin_lock_irqsave" },
+	{ 0xd35cce70, "_raw_spin_unlock_irqrestore" },
+	{ 0x5b8239ca, "__x86_return_thunk" },
+	{ 0xbdfb6dbb, "__fentry__" },
+	{ 0x122c3a7e, "_printk" },
+	{ 0x76800044, "module_layout" },
+};
+
+MODULE_INFO(depends, "");
+
+
+MODULE_INFO(srcversion, "13FF04EED34E7348D027C8D");
diff --git a/work/tp3/modules.order b/work/tp3/modules.order
new file mode 100644
index 0000000000000000000000000000000000000000..13e726a8e69115b02677ae5d97d0643856d122c2
--- /dev/null
+++ b/work/tp3/modules.order
@@ -0,0 +1,6 @@
+/root/Desktop/asee/work/tp3/sleep.o
+/root/Desktop/asee/work/tp3/example_mutex.o
+/root/Desktop/asee/work/tp3/example_spinlock.o
+/root/Desktop/asee/work/tp3/example_rwlock.o
+/root/Desktop/asee/work/tp3/example_atomic.o
+/root/Desktop/asee/work/tp3/pipebis3.o
diff --git a/work/tp3/pipebis.mod.c b/work/tp3/pipebis.mod.c
new file mode 100644
index 0000000000000000000000000000000000000000..bcfd385cf9f8e0cc5ac7d36f681e1c3de6f28b40
--- /dev/null
+++ b/work/tp3/pipebis.mod.c
@@ -0,0 +1,65 @@
+#include <linux/module.h>
+#define INCLUDE_VERMAGIC
+#include <linux/build-salt.h>
+#include <linux/elfnote-lto.h>
+#include <linux/export-internal.h>
+#include <linux/vermagic.h>
+#include <linux/compiler.h>
+
+#ifdef CONFIG_UNWINDER_ORC
+#include <asm/orc_header.h>
+ORC_HEADER;
+#endif
+
+BUILD_SALT;
+BUILD_LTO_INFO;
+
+MODULE_INFO(vermagic, VERMAGIC_STRING);
+MODULE_INFO(name, KBUILD_MODNAME);
+
+__visible struct module __this_module
+__section(".gnu.linkonce.this_module") = {
+	.name = KBUILD_MODNAME,
+	.init = init_module,
+#ifdef CONFIG_MODULE_UNLOAD
+	.exit = cleanup_module,
+#endif
+	.arch = MODULE_ARCH_INIT,
+};
+
+#ifdef CONFIG_RETPOLINE
+MODULE_INFO(retpoline, "Y");
+#endif
+
+
+
+static const struct modversion_info ____versions[]
+__used __section("__versions") = {
+	{ 0xfdfe3852, "class_destroy" },
+	{ 0x6bc3fbc0, "__unregister_chrdev" },
+	{ 0xecc78457, "kobject_put" },
+	{ 0x73895700, "__register_chrdev" },
+	{ 0xeb233a45, "__kmalloc" },
+	{ 0xfb890f0b, "class_create" },
+	{ 0x41b15bc9, "device_create" },
+	{ 0xa6ef1646, "kernel_kobj" },
+	{ 0x10bd90f2, "kobject_create_and_add" },
+	{ 0xa3efd5d1, "sysfs_create_file_ns" },
+	{ 0xbcab6ee6, "sscanf" },
+	{ 0x37a0cba, "kfree" },
+	{ 0xbdfb6dbb, "__fentry__" },
+	{ 0x5b8239ca, "__x86_return_thunk" },
+	{ 0xc3aaf0a9, "__put_user_1" },
+	{ 0x167e7f9d, "__get_user_1" },
+	{ 0x3c3ff9fd, "sprintf" },
+	{ 0x122c3a7e, "_printk" },
+	{ 0xab632ed, "module_put" },
+	{ 0x47143bb3, "try_module_get" },
+	{ 0xf23bcaeb, "device_destroy" },
+	{ 0x76800044, "module_layout" },
+};
+
+MODULE_INFO(depends, "");
+
+
+MODULE_INFO(srcversion, "0239DCAF7B987EAF91F373E");
diff --git a/work/tp3/pipebis3.c b/work/tp3/pipebis3.c
new file mode 100644
index 0000000000000000000000000000000000000000..9d3edcf8ae01ae06f1167e04f61ec2c4fea55360
--- /dev/null
+++ b/work/tp3/pipebis3.c
@@ -0,0 +1,317 @@
+/* 
+ * pipebis.c: Creates a read-only char device that says how many times 
+ * you have read from the dev file 
+ */ 
+ 
+#include <linux/atomic.h> 
+#include <linux/cdev.h> 
+#include <linux/delay.h> 
+#include <linux/device.h> 
+#include <linux/fs.h> 
+#include <linux/init.h> 
+#include <linux/kernel.h> /* for sprintf() */ 
+#include <linux/module.h> 
+#include <linux/printk.h> 
+#include <linux/types.h> 
+#include <linux/uaccess.h> /* for get_user and put_user */ 
+#include <linux/version.h> 
+#include <linux/wait.h> /* For putting processes to sleep and waking them up */  
+
+#include <asm/current.h> 
+#include <asm/errno.h> 
+ 
+/*  Prototypes - this would normally go in a .h file */ 
+static int device_open(struct inode *, struct file *); 
+static int device_release(struct inode *, struct file *); 
+static ssize_t device_read(struct file *, char __user *, size_t, loff_t *); 
+static ssize_t device_write(struct file *, const char __user *, size_t, 
+                            loff_t *); 
+ 
+#define SUCCESS 0 
+#define DEVICE_NAME "asee_mod" /* Dev name as it appears in /proc/devices   */ 
+#define BUF_LEN 16 /* Max length of the message from the device */ 
+ 
+/* Global variables are declared as static, so are global within the file. */ 
+
+static char *msg; /* The msg the device will give when asked */ 
+
+static struct kobject *pipebis_module;
+
+static int asee_buf_count = 0;
+
+static int asee_buf_size = BUF_LEN;
+
+static ssize_t asee_buf_size_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+    return sprintf(buf, "%d\n", asee_buf_size);
+}
+
+static ssize_t asee_buf_size_store(struct kobject *kobj, struct kobj_attribute *attr, char *buf, size_t count)
+{
+    int old_size = asee_buf_size;
+    sscanf(buf, "%du", &asee_buf_size);
+    if (asee_buf_size <= asee_buf_count) {
+        asee_buf_size = old_size;
+        pr_err("New size for buffer should be less than current content in it");
+        return count;
+    }
+
+    char * second_message = kcalloc(asee_buf_size, sizeof(char), GFP_KERNEL);
+    for(int cpt = 0; cpt < old_size; cpt++) {
+        second_message[cpt] = msg[cpt];
+    }
+    kfree(msg);
+    msg = second_message;
+    // TODO: incresae buffer size
+    return count;
+}
+
+static struct kobj_attribute asee_buf_size_attribute = __ATTR(asee_buf_size, 0660, asee_buf_size_show, (void *)asee_buf_size_store);
+
+
+static ssize_t asee_buf_count_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+    return sprintf(buf, "%d\n", asee_buf_count);
+}
+
+static ssize_t asee_buf_count_store(struct kobject *kobj, struct kobj_attribute *attr, char *buf, size_t count)
+{
+    return count;
+}
+ 
+static struct kobj_attribute asee_buf_count_attribute = __ATTR(asee_buf_count, 0660, asee_buf_count_show, (void *)asee_buf_count_store);
+
+static int major; /* major number assigned to our device driver */ 
+ 
+enum { 
+    CDEV_NOT_USED = 0, 
+    CDEV_EXCLUSIVE_OPEN = 1, 
+}; 
+ 
+/* Is device open? Used to prevent multiple access to device */ 
+static atomic_t already_open = ATOMIC_INIT(CDEV_NOT_USED); 
+static atomic_t already_full = ATOMIC_INIT(0); 
+static DECLARE_WAIT_QUEUE_HEAD(wait_full); 
+ 
+static atomic_t empty_buffer = ATOMIC_INIT(0); 
+static DECLARE_WAIT_QUEUE_HEAD(wait_empty);
+
+static struct class *cls; 
+ 
+static struct file_operations pipebis_fops = { 
+    .read = device_read, 
+    .write = device_write, 
+    .open = device_open, 
+    .release = device_release, 
+}; 
+ 
+static int __init pipebis_init(void) 
+{ 
+    major = register_chrdev(0, DEVICE_NAME, &pipebis_fops); 
+ 
+    if (major < 0) { 
+        pr_alert("Registering char device failed with %d\n", major); 
+        return major; 
+    } 
+ 
+    pr_info("I was assigned major number %d.\n", major); 
+
+    msg = kcalloc(asee_buf_size, sizeof(char), GFP_KERNEL);
+ 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) 
+    cls = class_create(DEVICE_NAME); 
+#else 
+    cls = class_create(THIS_MODULE, DEVICE_NAME); 
+#endif 
+    device_create(cls, NULL, MKDEV(major, 0), NULL, DEVICE_NAME); 
+ 
+    pr_info("Device created on /dev/%s\n", DEVICE_NAME); 
+    
+    pipebis_module = kobject_create_and_add("asee_mod", kernel_kobj);
+    if (!pipebis_module) return -ENOMEM;
+
+    int error = 0;
+    error = sysfs_create_file(pipebis_module, &asee_buf_size_attribute.attr);
+    error += sysfs_create_file(pipebis_module, &asee_buf_count_attribute.attr);
+    if (error) {
+        pr_info("failed to create a asee variable in /sys/kernel/asee_mod\n");
+        return error;
+    }
+
+    return SUCCESS; 
+} 
+ 
+static void __exit pipebis_exit(void) 
+{ 
+    device_destroy(cls, MKDEV(major, 0)); 
+    class_destroy(cls); 
+ 
+    /* Unregister the device */ 
+    unregister_chrdev(major, DEVICE_NAME); 
+    kobject_put(pipebis_module);
+} 
+ 
+/* Methods */ 
+
+/* Called when a process tries to open the device file, like 
+ * "sudo cat /dev/pipebis" 
+ */ 
+static int device_open(struct inode *inode, struct file *file) 
+{  
+   // if (atomic_cmpxchg(&already_open, CDEV_NOT_USED, CDEV_EXCLUSIVE_OPEN)) 
+    //    return -EBUSY; 
+
+    if ((file->f_flags & O_NONBLOCK) && atomic_read(&already_full)) 
+        return -EAGAIN;
+
+    if ((file->f_flags & O_NONBLOCK) && atomic_read(&empty_buffer)) 
+        return -EAGAIN;
+
+    try_module_get(THIS_MODULE); 
+ 
+    return SUCCESS; 
+} 
+ 
+/* Called when a process closes the device file. */ 
+static int device_release(struct inode *inode, struct file *file) 
+{ 
+    /* We're now ready for our next caller */ 
+    //atomic_set(&already_open, CDEV_NOT_USED); 
+ 
+    /* Decrement the usage count, or else once you opened the file, you will 
+     * never get rid of the module. 
+     */ 
+    module_put(THIS_MODULE); 
+ 
+    return SUCCESS; 
+} 
+
+
+
+/* Called when a process, which already opened the dev file, attempts to 
+ * read from it. 
+ */ 
+
+static int block_empty_buff(void) 
+{
+    while (atomic_cmpxchg(&empty_buffer, 0, 1)) { 
+        int i, is_sig = 0; 
+        
+        wait_event_interruptible(wait_empty, !atomic_read(&empty_buffer));    
+        
+        for (i = 0; i < _NSIG_WORDS && !is_sig; i++) {
+            is_sig = current->pending.signal.sig[i] & ~current->blocked.sig[i]; 
+        }
+        
+        if (is_sig) {
+            module_put(THIS_MODULE);
+            return -1;
+        }
+    }
+    return 0;
+}
+
+static int last_writen_bytes = 0;
+static int last_read_bytes = 0;
+static ssize_t device_read(struct file *filp, /* see include/linux/fs.h   */ 
+                           char __user *buffer, /* buffer to fill with data */ 
+                           size_t length, /* length of the buffer     */ 
+                           loff_t *offset) 
+{ 
+    /* Number of bytes actually written to the buffer */ 
+    int bytes_read = 0; 
+    char *msg_ptr = msg; 
+
+    if (asee_buf_count <= 0) {
+        if (block_empty_buff() < 0) return 0;
+    }
+ 
+    /* Actually put the data into the buffer */ 
+    while (asee_buf_count > 0) { 
+        if (last_read_bytes >= asee_buf_size) {
+            last_read_bytes = 0;
+        }
+        /* The buffer is in the user data segment, not the kernel 
+         * segment so "*" assignment won't work.  We have to use 
+         * put_user which copies data from the kernel data segment to 
+         * the user data segment. 
+         */ 
+        
+        put_user(*(msg_ptr + last_read_bytes), buffer++);
+        // Try to clear the read
+        *(msg_ptr + last_read_bytes) = '\0';
+        last_read_bytes++;
+        asee_buf_count--;
+        bytes_read++;
+        atomic_set(&already_full, 0); 
+        wake_up(&wait_full);
+        //if (asee_buf_count <= 0) {
+        //    if (block_empty_buff() < 0) return 0;
+        //}
+    } 
+    *offset = last_read_bytes; 
+ 
+    /* Most read functions return the number of bytes put into the buffer. */ 
+    return bytes_read; 
+} 
+
+static int block_full_buff(void) 
+{
+    while (atomic_cmpxchg(&already_full, 0, 1)) { 
+        int i, is_sig = 0; 
+        
+        wait_event_interruptible(wait_full, !atomic_read(&already_full));    
+        
+        for (i = 0; i < _NSIG_WORDS && !is_sig; i++) {
+            is_sig = current->pending.signal.sig[i] & ~current->blocked.sig[i]; 
+        }
+        
+        if (is_sig) {
+            module_put(THIS_MODULE);
+            return -1;
+        }
+    }
+    return 0;
+}
+ 
+/* Called when a process writes to dev file: echo "hi" > /dev/hello */ 
+static ssize_t device_write(struct file *filp, const char __user *buff, 
+                            size_t len, loff_t *off) 
+{ 
+    int bytes_writen = 0;
+
+    int current_bytes = last_writen_bytes;
+
+    if (asee_buf_count >= asee_buf_size) {
+        if ( block_full_buff() < 0 ) return 0;
+    }
+
+    for (int cpt = 0; cpt < len; cpt++) {
+        if (current_bytes >= asee_buf_size) {
+            current_bytes = 0;
+        }
+        get_user(*(msg + current_bytes), buff + cpt);
+        current_bytes++;
+        bytes_writen++;
+
+        atomic_set(&empty_buffer, 0); 
+        wake_up(&wait_empty);
+
+        if (asee_buf_count < asee_buf_size) {
+            asee_buf_count++;
+        } else {
+            if ( block_full_buff() < 0 ) return 0;
+        }
+    }
+    last_read_bytes = (last_read_bytes + bytes_writen) % asee_buf_count;
+
+    last_writen_bytes = current_bytes;
+    *off = last_writen_bytes; 
+
+    return bytes_writen; 
+} 
+ 
+module_init(pipebis_init); 
+module_exit(pipebis_exit); 
+ 
+MODULE_LICENSE("GPL");
diff --git a/work/tp3/pipebis3.mod.c b/work/tp3/pipebis3.mod.c
new file mode 100644
index 0000000000000000000000000000000000000000..1508ee4d1860b16736802e186644dd9882ca7251
--- /dev/null
+++ b/work/tp3/pipebis3.mod.c
@@ -0,0 +1,73 @@
+#include <linux/module.h>
+#define INCLUDE_VERMAGIC
+#include <linux/build-salt.h>
+#include <linux/elfnote-lto.h>
+#include <linux/export-internal.h>
+#include <linux/vermagic.h>
+#include <linux/compiler.h>
+
+#ifdef CONFIG_UNWINDER_ORC
+#include <asm/orc_header.h>
+ORC_HEADER;
+#endif
+
+BUILD_SALT;
+BUILD_LTO_INFO;
+
+MODULE_INFO(vermagic, VERMAGIC_STRING);
+MODULE_INFO(name, KBUILD_MODNAME);
+
+__visible struct module __this_module
+__section(".gnu.linkonce.this_module") = {
+	.name = KBUILD_MODNAME,
+	.init = init_module,
+#ifdef CONFIG_MODULE_UNLOAD
+	.exit = cleanup_module,
+#endif
+	.arch = MODULE_ARCH_INIT,
+};
+
+#ifdef CONFIG_RETPOLINE
+MODULE_INFO(retpoline, "Y");
+#endif
+
+
+
+static const struct modversion_info ____versions[]
+__used __section("__versions") = {
+	{ 0x92540fbf, "finish_wait" },
+	{ 0xf0fdf6cb, "__stack_chk_fail" },
+	{ 0x167e7f9d, "__get_user_1" },
+	{ 0xe2964344, "__wake_up" },
+	{ 0xc3aaf0a9, "__put_user_1" },
+	{ 0xf23bcaeb, "device_destroy" },
+	{ 0xfdfe3852, "class_destroy" },
+	{ 0x6bc3fbc0, "__unregister_chrdev" },
+	{ 0xecc78457, "kobject_put" },
+	{ 0x73895700, "__register_chrdev" },
+	{ 0x122c3a7e, "_printk" },
+	{ 0xeb233a45, "__kmalloc" },
+	{ 0xfb890f0b, "class_create" },
+	{ 0x41b15bc9, "device_create" },
+	{ 0xa6ef1646, "kernel_kobj" },
+	{ 0x10bd90f2, "kobject_create_and_add" },
+	{ 0xa3efd5d1, "sysfs_create_file_ns" },
+	{ 0xbcab6ee6, "sscanf" },
+	{ 0x37a0cba, "kfree" },
+	{ 0xbdfb6dbb, "__fentry__" },
+	{ 0x5b8239ca, "__x86_return_thunk" },
+	{ 0x3c3ff9fd, "sprintf" },
+	{ 0xab632ed, "module_put" },
+	{ 0x47143bb3, "try_module_get" },
+	{ 0x8470dec7, "pcpu_hot" },
+	{ 0xe2c17b5d, "__SCT__might_resched" },
+	{ 0xfe487975, "init_wait_entry" },
+	{ 0x1000e51, "schedule" },
+	{ 0x8c26d495, "prepare_to_wait_event" },
+	{ 0x76800044, "module_layout" },
+};
+
+MODULE_INFO(depends, "");
+
+
+MODULE_INFO(srcversion, "FC2D859DF4303E84366E606");
diff --git a/work/tp3/sleep.c b/work/tp3/sleep.c
new file mode 100644
index 0000000000000000000000000000000000000000..53905725507814f87eaf84e911977c7cc14fdfca
--- /dev/null
+++ b/work/tp3/sleep.c
@@ -0,0 +1,222 @@
+/* 
+ * sleep.c - create a /proc file, and if several processes try to open it 
+ * at the same time, put all but one to sleep. 
+ */ 
+ 
+#include <linux/atomic.h> 
+#include <linux/fs.h> 
+#include <linux/kernel.h> /* for sprintf() */ 
+#include <linux/module.h> /* Specifically, a module */ 
+#include <linux/printk.h> 
+#include <linux/proc_fs.h> /* Necessary because we use proc fs */ 
+#include <linux/types.h> 
+#include <linux/uaccess.h> /* for get_user and put_user */ 
+#include <linux/version.h> 
+#include <linux/wait.h> /* For putting processes to sleep and 
+                                   waking them up */  
+  
+#include <asm/current.h> 
+#include <asm/errno.h> 
+ 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) 
+#define HAVE_PROC_OPS 
+#endif 
+ 
+/* Here we keep the last message received, to prove that we can process our 
+ * input. 
+ */ 
+#define MESSAGE_LENGTH 80 
+static char message[MESSAGE_LENGTH]; 
+ 
+static struct proc_dir_entry *our_proc_file; 
+#define PROC_ENTRY_FILENAME "sleep" 
+ 
+/* Since we use the file operations struct, we can't use the special proc 
+ * output provisions - we have to use a standard read function, which is this 
+ * function. 
+ */ 
+static ssize_t module_output(struct file *file, /* see include/linux/fs.h   */ 
+                             char __user *buf, /* The buffer to put data to 
+                                                   (in the user segment)    */  
+                             size_t len, /* The length of the buffer */ 
+                             loff_t *offset) 
+{ 
+    static int finished = 0; 
+    int i; 
+    char output_msg[MESSAGE_LENGTH + 30]; 
+ 
+    /* Return 0 to signify end of file - that we have nothing more to say 
+     * at this point. 
+     */ 
+    if (finished) { 
+        finished = 0; 
+        return 0; 
+    } 
+ 
+    sprintf(output_msg, "Last input:%s\n", message); 
+    for (i = 0; i < len && output_msg[i]; i++) 
+        put_user(output_msg[i], buf + i); 
+ 
+    finished = 1; 
+    return i; /* Return the number of bytes "read" */ 
+} 
+ 
+/* This function receives input from the user when the user writes to the 
+ * /proc file. 
+ */ 
+static ssize_t module_input(struct file *file, /* The file itself */ 
+                            const char __user *buf, /* The buffer with input */ 
+                            size_t length, /* The buffer's length */ 
+                            loff_t *offset) /* offset to file - ignore */ 
+{ 
+    int i; 
+ 
+    /* Put the input into Message, where module_output will later be able 
+     * to use it. 
+     */ 
+    for (i = 0; i < MESSAGE_LENGTH - 1 && i < length; i++) 
+        get_user(message[i], buf + i); 
+    /* we want a standard, zero terminated string */ 
+    message[i] = '\0'; 
+ 
+    /* We need to return the number of input characters used */ 
+    return i; 
+} 
+ 
+/* 1 if the file is currently open by somebody */ 
+static atomic_t already_open = ATOMIC_INIT(0); 
+ 
+/* Queue of processes who want our file */ 
+static DECLARE_WAIT_QUEUE_HEAD(waitq); 
+ 
+/* Called when the /proc file is opened */ 
+static int module_open(struct inode *inode, struct file *file) 
+{ 
+    /* If the file's flags include O_NONBLOCK, it means the process does not 
+     * want to wait for the file. In this case, if the file is already open, 
+     * we should fail with -EAGAIN, meaning "you will have to try again", 
+     * instead of blocking a process which would rather stay awake. 
+     */ 
+    if ((file->f_flags & O_NONBLOCK) && atomic_read(&already_open)) 
+        return -EAGAIN; 
+ 
+    /* This is the correct place for try_module_get(THIS_MODULE) because if 
+     * a process is in the loop, which is within the kernel module, 
+     * the kernel module must not be removed. 
+     */ 
+    try_module_get(THIS_MODULE); 
+ 
+    while (atomic_cmpxchg(&already_open, 0, 1)) { 
+        int i, is_sig = 0; 
+ 
+        /* This function puts the current process, including any system 
+         * calls, such as us, to sleep.  Execution will be resumed right 
+         * after the function call, either because somebody called 
+         * wake_up(&waitq) (only module_close does that, when the file 
+         * is closed) or when a signal, such as Ctrl-C, is sent 
+         * to the process 
+         */ 
+        wait_event_interruptible(waitq, !atomic_read(&already_open)); 
+ 
+        /* If we woke up because we got a signal we're not blocking, 
+         * return -EINTR (fail the system call).  This allows processes 
+         * to be killed or stopped. 
+         */ 
+        for (i = 0; i < _NSIG_WORDS && !is_sig; i++) 
+            is_sig = current->pending.signal.sig[i] & ~current->blocked.sig[i]; 
+ 
+        if (is_sig) { 
+            /* It is important to put module_put(THIS_MODULE) here, because 
+             * for processes where the open is interrupted there will never 
+             * be a corresponding close. If we do not decrement the usage 
+             * count here, we will be left with a positive usage count 
+             * which we will have no way to bring down to zero, giving us 
+             * an immortal module, which can only be killed by rebooting 
+             * the machine. 
+             */ 
+            module_put(THIS_MODULE); 
+            return -EINTR; 
+        } 
+    } 
+ 
+    return 0; /* Allow the access */ 
+} 
+ 
+/* Called when the /proc file is closed */ 
+static int module_close(struct inode *inode, struct file *file) 
+{ 
+    /* Set already_open to zero, so one of the processes in the waitq will 
+     * be able to set already_open back to one and to open the file. All 
+     * the other processes will be called when already_open is back to one, 
+     * so they'll go back to sleep. 
+     */ 
+    atomic_set(&already_open, 0); 
+ 
+    /* Wake up all the processes in waitq, so if anybody is waiting for the 
+     * file, they can have it. 
+     */ 
+    wake_up(&waitq); 
+ 
+    module_put(THIS_MODULE); 
+ 
+    return 0; /* success */ 
+} 
+ 
+/* Structures to register as the /proc file, with pointers to all the relevant 
+ * functions. 
+ */ 
+ 
+/* File operations for our proc file. This is where we place pointers to all 
+ * the functions called when somebody tries to do something to our file. NULL 
+ * means we don't want to deal with something. 
+ */ 
+#ifdef HAVE_PROC_OPS 
+static const struct proc_ops file_ops_4_our_proc_file = { 
+    .proc_read = module_output, /* "read" from the file */ 
+    .proc_write = module_input, /* "write" to the file */ 
+    .proc_open = module_open, /* called when the /proc file is opened */ 
+    .proc_release = module_close, /* called when it's closed */ 
+    .proc_lseek = noop_llseek, /* return file->f_pos */ 
+}; 
+#else 
+static const struct file_operations file_ops_4_our_proc_file = { 
+    .read = module_output, 
+    .write = module_input, 
+    .open = module_open, 
+    .release = module_close, 
+    .llseek = noop_llseek, 
+}; 
+#endif 
+ 
+/* Initialize the module - register the proc file */ 
+static int __init sleep_init(void) 
+{ 
+    our_proc_file = 
+        proc_create(PROC_ENTRY_FILENAME, 0644, NULL, &file_ops_4_our_proc_file); 
+    if (our_proc_file == NULL) { 
+        pr_debug("Error: Could not initialize /proc/%s\n", PROC_ENTRY_FILENAME); 
+        return -ENOMEM; 
+    } 
+    proc_set_size(our_proc_file, 80); 
+    proc_set_user(our_proc_file, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID); 
+ 
+    pr_info("/proc/%s created\n", PROC_ENTRY_FILENAME); 
+ 
+    return 0; 
+} 
+ 
+/* Cleanup - unregister our file from /proc.  This could get dangerous if 
+ * there are still processes waiting in waitq, because they are inside our 
+ * open function, which will get unloaded. I'll explain how to avoid removal 
+ * of a kernel module in such a case in chapter 10. 
+ */ 
+static void __exit sleep_exit(void) 
+{ 
+    remove_proc_entry(PROC_ENTRY_FILENAME, NULL); 
+    pr_debug("/proc/%s removed\n", PROC_ENTRY_FILENAME); 
+} 
+ 
+module_init(sleep_init); 
+module_exit(sleep_exit); 
+ 
+MODULE_LICENSE("GPL");
\ No newline at end of file
diff --git a/work/tp3/sleep.mod.c b/work/tp3/sleep.mod.c
new file mode 100644
index 0000000000000000000000000000000000000000..af9ab7a81f87e72c192416195b488c1d5c43b075
--- /dev/null
+++ b/work/tp3/sleep.mod.c
@@ -0,0 +1,67 @@
+#include <linux/module.h>
+#define INCLUDE_VERMAGIC
+#include <linux/build-salt.h>
+#include <linux/elfnote-lto.h>
+#include <linux/export-internal.h>
+#include <linux/vermagic.h>
+#include <linux/compiler.h>
+
+#ifdef CONFIG_UNWINDER_ORC
+#include <asm/orc_header.h>
+ORC_HEADER;
+#endif
+
+BUILD_SALT;
+BUILD_LTO_INFO;
+
+MODULE_INFO(vermagic, VERMAGIC_STRING);
+MODULE_INFO(name, KBUILD_MODNAME);
+
+__visible struct module __this_module
+__section(".gnu.linkonce.this_module") = {
+	.name = KBUILD_MODNAME,
+	.init = init_module,
+#ifdef CONFIG_MODULE_UNLOAD
+	.exit = cleanup_module,
+#endif
+	.arch = MODULE_ARCH_INIT,
+};
+
+#ifdef CONFIG_RETPOLINE
+MODULE_INFO(retpoline, "Y");
+#endif
+
+
+
+static const struct modversion_info ____versions[]
+__used __section("__versions") = {
+	{ 0x122c3a7e, "_printk" },
+	{ 0x2cf56265, "__dynamic_pr_debug" },
+	{ 0xe2964344, "__wake_up" },
+	{ 0xab632ed, "module_put" },
+	{ 0x4c37b7b3, "remove_proc_entry" },
+	{ 0x3c3ff9fd, "sprintf" },
+	{ 0xc3aaf0a9, "__put_user_1" },
+	{ 0xf0fdf6cb, "__stack_chk_fail" },
+	{ 0x47143bb3, "try_module_get" },
+	{ 0x8470dec7, "pcpu_hot" },
+	{ 0xe2c17b5d, "__SCT__might_resched" },
+	{ 0xfe487975, "init_wait_entry" },
+	{ 0x1000e51, "schedule" },
+	{ 0x8c26d495, "prepare_to_wait_event" },
+	{ 0x92540fbf, "finish_wait" },
+	{ 0xfcda5799, "noop_llseek" },
+	{ 0xbdfb6dbb, "__fentry__" },
+	{ 0x167e7f9d, "__get_user_1" },
+	{ 0x5b8239ca, "__x86_return_thunk" },
+	{ 0x87a21cb3, "__ubsan_handle_out_of_bounds" },
+	{ 0x1fb706c, "proc_create" },
+	{ 0xb093cc6c, "proc_set_size" },
+	{ 0xa4e0184b, "proc_set_user" },
+	{ 0x76800044, "module_layout" },
+};
+
+MODULE_INFO(depends, "");
+
+
+MODULE_INFO(srcversion, "54ECDB7965AE96459D8F160");