Usporedba prema "02-simple-device" (napravljen je diff, ali onda maknuto sve što ne prikazuje novosti; ne može se ovaj diff ovako aplicirati - mnoge stvari nedostaju!) u config.h ----------- +#define PIPE_SIZE 64 +#define MAX_THREADS 5 +struct pipe { + size_t pipe_size; + size_t max_threads; + size_t thread_cnt; + struct kfifo fifo; + struct semaphore cs_readers; //kritični odsječak za čitače - čitaju jedan po jedan! + struct semaphore empty; //ako nema ništa u cijevi čitač koji je u KO čeka + int reader_waiting; //čeka li čitač? + struct semaphore cs_writers; //kritični odsječak za pisače - pišu jedan po jedan! + struct semaphore full; //ako je cijev puna pisač koji je u KO čeka + int writter_waiting; //čeka li pisač? + struct mutex lock; //za medjusobno iskljucivanje }; /* Device driver */ struct shofer_dev { - struct buffer *buffer; /* Pointer to buffer */ + struct pipe pipe; /* cijev */ }; + u shofer.c ----------- +static int pipe_size = PIPE_SIZE; +static int max_threads = MAX_THREADS; + +module_param(pipe_size, int, S_IRUGO); +MODULE_PARM_DESC(pipe_size, "Pipe size"); +module_param(max_threads, int, S_IRUGO); +MODULE_PARM_DESC(max_threads, "Maximal number of threads simultaneously using message queue"); +int pipe_init(struct pipe *pipe, size_t pipe_size, size_t max_threads) +{ + int ret; + ret = kfifo_alloc(&pipe->fifo, pipe_size, GFP_KERNEL); + if (ret) { + klog(KERN_NOTICE, "kfifo_alloc failed"); + return ret; + } + pipe->pipe_size = pipe_size; + pipe->max_threads = max_threads; + pipe->thread_cnt = 0; + + sema_init(&pipe->cs_readers, 1); + sema_init(&pipe->cs_writers, 1); + sema_init(&pipe->empty, 0); + sema_init(&pipe->full, 1); + pipe->reader_waiting = 0; + pipe->writter_waiting = 0; + + mutex_init(&pipe->lock); + + return 0; +} + +static void pipe_delete(struct pipe *pipe) +{ + //todo - obrisi sve poruke ako ih ima + kfifo_free(&pipe->fifo); } + /* initialize the pipe */ + if (pipe_init(&shofer->pipe, pipe_size, max_threads)) { + *retval = -ENOMEM; + kfree(shofer); + return NULL; + } + pipe_delete(&shofer->pipe); +/* Called when the process calls "open" on this device */ static int shofer_open(struct inode *inode, struct file *filp) { + if (shofer->pipe.thread_cnt == shofer->pipe.max_threads) + return -EBUSY; + + shofer->pipe.thread_cnt++; + return 0; } /* Called when a process performs "close" operation */ static int shofer_release(struct inode *inode, struct file *filp) { + struct shofer_dev *shofer = filp->private_data; + shofer->pipe.thread_cnt--; + + return 0; +} + +/* Pročitaj nešto iz cijevi */ static ssize_t shofer_read(struct file *filp, char __user *ubuf, size_t count, loff_t *f_pos /* ignoring f_pos */) { + struct pipe *pipe = &shofer->pipe; + struct kfifo *fifo = &pipe->fifo; + if ( (filp->f_flags & O_ACCMODE) != O_RDONLY) + return -EPERM; + + if (down_interruptible(&pipe->cs_readers)) + return -ERESTARTSYS; //čekanje prekinuto signalom + + //uđi u KO (za cijev) + while(1) { + if (mutex_lock_interruptible(&pipe->lock)) { + //čekanje na ulaz u KO prekinuto signalom + up(&pipe->cs_readers); //pusti idućeg čitača + return -ERESTARTSYS; + } + if (kfifo_is_empty(fifo)) { + pipe->reader_waiting = 1; + mutex_unlock(&pipe->lock); //privremeno izađi iz KO za cijev + if (down_interruptible(&pipe->empty)) { //čekaj da se nešto stavi + up(&pipe->cs_readers); + return -ERESTARTSYS; + } + } + else break; + } + pipe->reader_waiting = 0; + if (pipe->writter_waiting) + up(&pipe->full); //ako neki pisač čeka, neka sad proba opet + + mutex_unlock(&pipe->lock); //izađi iz KO + + up(&pipe->cs_readers); return retval; } +/* Stavi poruku u red */ static ssize_t shofer_write(struct file *filp, const char __user *ubuf, size_t count, loff_t *f_pos /* ignoring f_pos */) { + struct pipe *pipe = &shofer->pipe; + struct kfifo *fifo = &pipe->fifo; + if ( (filp->f_flags & O_ACCMODE) != O_WRONLY) + return -EPERM; + + if (count > pipe->pipe_size) + return -EFBIG; + + if (down_interruptible(&pipe->cs_writers)) return -ERESTARTSYS; + //uđi u KO (za cijev) + while(1) { + if (mutex_lock_interruptible(&pipe->lock)) { + //čekanje na ulaz u KO prekinuto signalom + up(&pipe->cs_writers); //pusti idućeg pisača + return -ERESTARTSYS; + } + if (kfifo_avail(fifo) < count) { + pipe->writter_waiting = 1; + mutex_unlock(&pipe->lock); //privremeno izađi iz KO za cijev + if (down_interruptible(&pipe->full)) { //čekaj da se nešto uzme + up(&pipe->cs_writers); //pusti idućeg pisača + return -ERESTARTSYS; + } + } + else break; + } + pipe->writter_waiting = 0; + if (pipe->reader_waiting) + up(&pipe->empty); //ako neki čitač čeka, neka sad proba opet + + mutex_unlock(&pipe->lock); //izađi iz KO + + up(&pipe->cs_writers); return retval; } Programi za testiranje: citac.c -------- #include #include #include #include #include #include #include #define CIJEV "/dev/shofer" #define MAXSZ 16 int main(int argc, char *argv[]) { int fp; char buffer[MAXSZ]; size_t size; long pid = (long) getpid(); fp = open(CIJEV, O_RDONLY); if (fp == -1) { perror("Nisam otvorio cjevovod! Greska: "); return -1; } while(1) { memset(buffer, 0, MAXSZ); printf("Citac %ld poziva read\n", pid); size = read(fp, buffer, MAXSZ); if (size == -1) { perror("Greska pri citanju! Greska: "); break; } printf("Citac %ld procitao (%ld): %s\n", pid, size, buffer); sleep(1); } return -1; } pisac.c ------- #include #include #include #include #include #include #include #define RED "/dev/shofer" #define MAXSZ 64 void gen_text(char *text, size_t size) { int i; for (i = 0; i < size; i++) text[i] = 'A' + random() % ('Z' - 'A'); } int main(int argc, char *argv[]) { int fp; char buffer[MAXSZ]; size_t size; long pid = (long) getpid(); fp = open(RED, O_WRONLY); if (fp == -1) { perror("Nisam otvorio cjevovod! Greska: "); return -1; } srandom(pid); while(1) { memset(buffer, 0, MAXSZ); size = MAXSZ / 3 + random() % (2 * MAXSZ / 3); gen_text(buffer, size); printf("Pisac %ld poziva write s tekstom (%ld): %s\n", pid, size, buffer); size = write(fp, buffer, size); if (size == -1) { perror("Greska pri pisanju! Greska: "); break; } printf("Pisac %ld poslao (%ld): %s\n", pid, size, buffer); sleep(2); } return -1; }