Thu Apr 30 00:48:10 2020 UTC ()
New kernel example module written by Ayushi Sharma


(christos)
diff -r1.10 -r1.11 src/sys/modules/examples/Makefile
diff -r1.14 -r1.15 src/sys/modules/examples/README
diff -r1.3 -r1.4 src/sys/modules/examples/ping/ping.c
diff -r0 -r1.1 src/sys/modules/examples/pollpal/Makefile
diff -r0 -r1.1 src/sys/modules/examples/pollpal/cmd_pollpal.c
diff -r0 -r1.1 src/sys/modules/examples/pollpal/pollpal.c

cvs diff -r1.10 -r1.11 src/sys/modules/examples/Makefile (expand / switch to unified diff)

--- src/sys/modules/examples/Makefile 2020/04/04 21:15:04 1.10
+++ src/sys/modules/examples/Makefile 2020/04/30 00:48:10 1.11
@@ -1,20 +1,21 @@ @@ -1,20 +1,21 @@
1# $NetBSD: Makefile,v 1.10 2020/04/04 21:15:04 kamil Exp $ 1# $NetBSD: Makefile,v 1.11 2020/04/30 00:48:10 christos Exp $
2 2
3.include <bsd.own.mk> 3.include <bsd.own.mk>
4 4
5SUBDIR+= current_time 5SUBDIR+= current_time
6SUBDIR+= executor 6SUBDIR+= executor
7SUBDIR+= fopsmapper # Needs an additional helper program 7SUBDIR+= fopsmapper # Needs an additional helper program
8SUBDIR+= hello 8SUBDIR+= hello
9#SUBDIR+= luahello # Nothing to build here, only text files 9#SUBDIR+= luahello # Nothing to build here, only text files
10SUBDIR+= luareadhappy # Needs an additional Lua script 10SUBDIR+= luareadhappy # Needs an additional Lua script
11SUBDIR+= mapper # Needs an additional helper program 11SUBDIR+= mapper # Needs an additional helper program
12SUBDIR+= panic_string # Crashes the system 12SUBDIR+= panic_string # Crashes the system
13SUBDIR+= ping # Needs an additional helper program 13SUBDIR+= ping # Needs an additional helper program
14SUBDIR+= ping_block # Needs an additional helper program 14SUBDIR+= ping_block # Needs an additional helper program
 15SUBDIR+= pollpal # Needs an additional helper program
15SUBDIR+= properties 16SUBDIR+= properties
16SUBDIR+= readhappy 17SUBDIR+= readhappy
17SUBDIR+= readhappy_mpsafe # Contains an additional helper program 18SUBDIR+= readhappy_mpsafe # Contains an additional helper program
18SUBDIR+= sysctl 19SUBDIR+= sysctl
19 20
20.include <bsd.subdir.mk> 21.include <bsd.subdir.mk>

cvs diff -r1.14 -r1.15 src/sys/modules/examples/README (expand / switch to unified diff)

--- src/sys/modules/examples/README 2020/04/04 21:15:04 1.14
+++ src/sys/modules/examples/README 2020/04/30 00:48:10 1.15
@@ -1,32 +1,33 @@ @@ -1,32 +1,33 @@
1 $NetBSD: README,v 1.14 2020/04/04 21:15:04 kamil Exp $ 1 $NetBSD: README,v 1.15 2020/04/30 00:48:10 christos Exp $
2 2
3 Kernel Developer's Manual 3 Kernel Developer's Manual
4 4
5DESCRIPTION 5DESCRIPTION
6 The kernel example dynamic modules. 6 The kernel example dynamic modules.
7 7
8 This directory contains the following example modules: 8 This directory contains the following example modules:
9 * current_time - prints current date and time in GMT/UTC 9 * current_time - prints current date and time in GMT/UTC
10 * executor - basic implementation of callout and RUN_ONCE 10 * executor - basic implementation of callout and RUN_ONCE
11 * fopsmapper - basic implementation of mmap with fileops fo_mmap 11 * fopsmapper - basic implementation of mmap with fileops fo_mmap
12 * hello - the simplest `hello world' module 12 * hello - the simplest `hello world' module
13 * luahello - the simplest `hello world' Lua module 13 * luahello - the simplest `hello world' Lua module
14 * luareadhappy - demonstrates calling Lua code from C 14 * luareadhappy - demonstrates calling Lua code from C
15 * mapper - basic implementation of mmap 15 * mapper - basic implementation of mmap
16 * panic_string - shows how panic is being called through a device 16 * panic_string - shows how panic is being called through a device
17 * ping - basic ioctl(9) 17 * ping - basic ioctl(9)
18 * ping_block - basic ioctl(9) with a block device 18 * ping_block - basic ioctl(9) with a block device
19 * properties - handle incoming properties during the module load 19 * properties - handle incoming properties during the module load
 20 * pollpal - implementation of basic poll(9) using palindrome
20 * readhappy - basic implementation of read(9) with happy numbers 21 * readhappy - basic implementation of read(9) with happy numbers
21 * readhappy_mpsafe- demonstrates how to make a module MPSAFE 22 * readhappy_mpsafe- demonstrates how to make a module MPSAFE
22 * sysctl - demonstrates adding a sysctl handle dynamically 23 * sysctl - demonstrates adding a sysctl handle dynamically
23 24
24 To build the examples you need a local copy of NetBSD sources. You also 25 To build the examples you need a local copy of NetBSD sources. You also
25 need the comp set with toolchain. To build the module just enter a 26 need the comp set with toolchain. To build the module just enter a
26 directory with example modules and use make(1): 27 directory with example modules and use make(1):
27 28
28 # make 29 # make
29 30
30 To load, unload, and stat the module use modload(8), modunload(8) and 31 To load, unload, and stat the module use modload(8), modunload(8) and
31 modstat(8). 32 modstat(8).
32 33
@@ -72,15 +73,18 @@ HISTORY @@ -72,15 +73,18 @@ HISTORY
72 73
73 The mapper module first appeared in NetBSD 9.0 and was authored by 74 The mapper module first appeared in NetBSD 9.0 and was authored by
74 Akul Pillai. 75 Akul Pillai.
75  76
76 The ping_block module first appeared in NetBSD 10.0 and was authored by 77 The ping_block module first appeared in NetBSD 10.0 and was authored by
77 Nisarg Joshi. 78 Nisarg Joshi.
78 79
79 The fopsmapper module first appeared in NetBSD 10.0 and was authored by 80 The fopsmapper module first appeared in NetBSD 10.0 and was authored by
80 Aditya Vardhan Padala. 81 Aditya Vardhan Padala.
81 82
82 The current_time module first appeared in NetBSD 10.0 and was authored by 83 The current_time module first appeared in NetBSD 10.0 and was authored by
83 Apurva Nandan. 84 Apurva Nandan.
84 85
 86 The pollpall module first appeared in NetBSD 10.0 and was authored by
 87 Ayushi Sharma.
 88
85AUTHORS 89AUTHORS
86 This document was written by Kamil Rytarowski. 90 This document was written by Kamil Rytarowski.

cvs diff -r1.3 -r1.4 src/sys/modules/examples/ping/ping.c (expand / switch to unified diff)

--- src/sys/modules/examples/ping/ping.c 2020/02/05 14:10:46 1.3
+++ src/sys/modules/examples/ping/ping.c 2020/04/30 00:48:10 1.4
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: ping.c,v 1.3 2020/02/05 14:10:46 pgoyette Exp $ */ 1/* $NetBSD: ping.c,v 1.4 2020/04/30 00:48:10 christos Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2015 The NetBSD Foundation, Inc. 4 * Copyright (c) 2015 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -17,33 +17,35 @@ @@ -17,33 +17,35 @@
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29#include <sys/cdefs.h> 29#include <sys/cdefs.h>
30__KERNEL_RCSID(0, "$NetBSD: ping.c,v 1.3 2020/02/05 14:10:46 pgoyette Exp $"); 30__KERNEL_RCSID(0, "$NetBSD: ping.c,v 1.4 2020/04/30 00:48:10 christos Exp $");
31 31
 32#define DDB
32#include <sys/param.h> 33#include <sys/param.h>
33#include <sys/conf.h> 34#include <sys/conf.h>
34#include <sys/device.h> 35#include <sys/device.h>
35#include <sys/kernel.h> 36#include <sys/kernel.h>
36#include <sys/module.h> 37#include <sys/module.h>
 38#include <sys/systm.h>
37 39
38#include "ping.h" 40#include "ping.h"
39 41
40/* 42/*
41 * Create a device /dev/ping in order to test this module. 43 * Create a device /dev/ping in order to test this module.
42 * 44 *
43 * To use this device you need to do: 45 * To use this device you need to do:
44 * mknod /dev/ping c 351 0 46 * mknod /dev/ping c 351 0
45 * 47 *
46 */ 48 */
47 49
48dev_type_open(ping_open); 50dev_type_open(ping_open);
49dev_type_close(ping_close); 51dev_type_close(ping_close);
@@ -89,26 +91,27 @@ ping_close(dev_t self __unused, int flag @@ -89,26 +91,27 @@ ping_close(dev_t self __unused, int flag
89{ 91{
90 --sc.refcnt; 92 --sc.refcnt;
91 93
92 return 0; 94 return 0;
93} 95}
94 96
95int 97int
96ping_ioctl(dev_t self __unused, u_long cmd, void *data, int flag, 98ping_ioctl(dev_t self __unused, u_long cmd, void *data, int flag,
97 struct lwp *l __unused) 99 struct lwp *l __unused)
98{ 100{
99 switch(cmd) { 101 switch(cmd) {
100 case CMD_PING: 102 case CMD_PING:
101 printf("ping: pong!\n"); 103 printf("ping: pong!\n");
 104 Debugger();
102 return 0; 105 return 0;
103 default: 106 default:
104 return ENOTTY; 107 return ENOTTY;
105 } 108 }
106} 109}
107 110
108MODULE(MODULE_CLASS_MISC, ping, NULL); 111MODULE(MODULE_CLASS_MISC, ping, NULL);
109 112
110static int 113static int
111ping_modcmd(modcmd_t cmd, void *arg __unused) 114ping_modcmd(modcmd_t cmd, void *arg __unused)
112{ 115{
113 /* The major should be verified and changed if needed to avoid 116 /* The major should be verified and changed if needed to avoid
114 * conflicts with other devices. */ 117 * conflicts with other devices. */

File Added: src/sys/modules/examples/pollpal/Makefile
#   $NetBSD: Makefile,v 1.1 2020/04/30 00:48:10 christos Exp $

.include "../Makefile.inc"

#S?=	/usr/src/sys

KMOD=   pollpal
SRCS=   pollpal.c

.include <bsd.kmodule.mk>

# To make use of this module, you'll need to separately build the
# cmd_pollpall program, with a Makefile similar to
#
#   MKMAN=  NO
#   PROG=   cmd_pollpal
#   .include <bsd.prog.mk>


File Added: src/sys/modules/examples/pollpal/cmd_pollpal.c
/*	$NetBSD: cmd_pollpal.c,v 1.1 2020/04/30 00:48:10 christos Exp $	*/

/*-
 * Copyright (c) 2020 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/cdefs.h>
__RCSID("$NetBSD: cmd_pollpal.c,v 1.1 2020/04/30 00:48:10 christos Exp $");

#include <sys/mman.h>

#include <errno.h>
#include <err.h>
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>

#define BUFFLEN 100
#define TIMEOUT 10000

static int fd; 

static __dead __printflike(2, 3) void 
done(int e, const char *msg, ...)
{
	if (msg) {
		va_list ap;

		va_start(ap, msg);
		verr(e, msg, ap);
		/*NOTREACHED*/
		va_end(ap);
	}
	exit(e);
}
	
static __dead void 
handler(int sig)
{
	done(EXIT_SUCCESS, NULL);
}

static const char dev[] = "/dev/pollpal";
static const char wbuf[] = "abcdefghijklmnopqrstuvwxyz";

int 
main(int argc, char **argv)
{
	struct pollfd fds;
	ssize_t ret;
	size_t i;
	char rbuf[BUFFLEN];

	setprogname(argv[0]);

	fd = open(dev, O_RDWR, 0);
	if (fd == -1)
		err(EXIT_FAILURE, "open `%s'", dev);

	fds.fd = fd;
	fds.events = POLLOUT|POLLIN;

	signal(SIGINT, handler);
	for (i = 1; i <= 100; i++) {
		ret = poll(&fds, 1, TIMEOUT);
		if (ret == -1) {
			if (errno == EINTR)
				continue;
			done(EXIT_FAILURE, "poll");
		}
		printf("Poll_executing %zu times\n", i);
		if (ret == 0) {
			printf("%d seconds elapsed \n.TIMEOUT.\n",
			    TIMEOUT / 1000);
			done(EXIT_SUCCESS, NULL);
		}
		
		if (fds.revents & (POLLERR | POLLHUP | POLLNVAL)) 
			done(EXIT_FAILURE, "ERR|HUP|NVAL");
		
		if (fds.revents & POLLOUT) {
			do {
				ret = write(fd, wbuf, sizeof(wbuf) - 1);
			} while (ret == -1 && errno == EINTR);
			
			if (ret == -1) {
				done(EXIT_FAILURE, "write");
			}
			printf("Wrote %zd byte\n", ret);
		}
		if (fds.revents & POLLIN) {
			memset(rbuf, 0, BUFFLEN);
			do {
				ret = read(fd, rbuf, BUFFLEN);
			} while (ret == -1 && errno == EINTR);
			if (ret == -1) {
				done(EXIT_FAILURE, "read");
			}
			printf("Read %zd bytes\n", ret);
		}
	}
	done(EXIT_SUCCESS, NULL);
}

File Added: src/sys/modules/examples/pollpal/pollpal.c
/*	$NetBSD: pollpal.c,v 1.1 2020/04/30 00:48:10 christos Exp $	*/ 

/*-
* Copyright (c) 2020 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/ 

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: pollpal.c,v 1.1 2020/04/30 00:48:10 christos Exp $");

#include <sys/module.h>
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>

#include <sys/condvar.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/mutex.h>
#include <sys/kmem.h>
#include <sys/poll.h>
#include <sys/select.h>

/* 
 * Create a device /dev/pollpal
 *
 * To use this device you need to do:
 * 	mknod /dev/pollpal c 351 0
 *
 */ 

dev_type_open(pollpal_open);

static struct cdevsw pollpal_cdevsw = {
	.d_open = pollpal_open,
	.d_close = noclose,
	.d_read = noread,
	.d_write = nowrite,
	.d_ioctl = noioctl,
	.d_stop = nostop,
	.d_tty = notty,
	.d_poll = nopoll,
	.d_mmap = nommap,
	.d_kqfilter = nokqfilter,
	.d_discard = nodiscard,
	.d_flag = D_OTHER
};

static int	pollpal_nopen = 0;

static int	pollpal_close(file_t *);
static int	pollpal_write(file_t *, off_t *, struct uio *, kauth_cred_t,
    int);
static int	pollpal_read(file_t *, off_t *, struct uio *, kauth_cred_t,
    int);
static int	pollpal_poll(file_t *, int);

const struct fileops pollpal_fileops = {
	.fo_read = pollpal_read,
	.fo_write = pollpal_write,
	.fo_ioctl = fbadop_ioctl,
	.fo_fcntl = fnullop_fcntl,
	.fo_poll = pollpal_poll,
	.fo_stat = fbadop_stat,
	.fo_close = pollpal_close,
	.fo_kqfilter = fnullop_kqfilter,
	.fo_restart = fnullop_restart,
};

typedef struct pollpal_softc {
	kmutex_t lock;
	kcondvar_t sc_cv;
	struct selinfo psel;
	char *buf;
	size_t buf_len;
	/* Device can have two states 1.READ_WAITING, 2.WRITE_WAITING. */ 
	enum states {
		READ_WAITING = 0,
		WRITE_WAITING = 1
	} sc_state;
} pal_t;

static int 
check_pal(const char *str, size_t len)
{
	size_t n;
	
	n = 0;
	
	while (n <= len / 2) {
		if (str[n] != str[len - n - 1])
			return 0;

		n++;
	} 
	
	return 1;
} 

int 
pollpal_open(dev_t dev, int flag, int mode, struct lwp *l __unused)
{
	struct file *fp;
	int error, fd;
	pal_t *pl;
	
	error = fd_allocfile(&fp, &fd);
	if (error)
		return error;

	++pollpal_nopen;

	pl = kmem_zalloc(sizeof(*pl), KM_SLEEP);

	pl->sc_state = READ_WAITING;
	mutex_init(&pl->lock, MUTEX_DEFAULT, IPL_NONE);
	cv_init(&pl->sc_cv, "sc_cv");
	selinit(&pl->psel);

	return fd_clone(fp, fd, flag, &pollpal_fileops, pl);
} 

int 
pollpal_close(file_t * fp)
{
	pal_t * pl = fp->f_data;
	KASSERT(pl != NULL);
	
	if (pl->buf != NULL)
		kmem_free(pl->buf, pl->buf_len);
	
	seldestroy(&pl->psel);
	cv_destroy(&pl->sc_cv);
	mutex_destroy(&pl->lock);
	kmem_free(pl, sizeof(*pl));

	--pollpal_nopen;	

	return 0;
} 

/*
 * Device would write only in READ_WAITING state and then update the state to 
 * WRITE_WAITING.
 */ 
int
pollpal_write(file_t *fp, off_t *offset, struct uio *uio, kauth_cred_t cred,
    int flag)
{
	pal_t *pl = fp->f_data;
	int error;
	
	error = 0;
	
	/* To ensure that only single process can write in device at a time. */ 
	mutex_enter(&pl->lock);
	cv_broadcast(&pl->sc_cv);
	switch (pl->sc_state) {
	case READ_WAITING:
		pl->sc_state = WRITE_WAITING;
		selnotify(&pl->psel, POLLOUT | POLLWRNORM, 0);
		while (pl->sc_state == WRITE_WAITING) {
			if (pl->buf) {
				error = cv_wait_sig(&pl->sc_cv, &pl->lock);
				if (error)
					goto ret;

			}

			pl->buf_len = uio->uio_iov->iov_len;
			pl->buf = kmem_alloc(pl->buf_len, KM_SLEEP);
			uiomove(pl->buf, pl->buf_len, uio);
			printf("Use cat to know the result.\n");
			break;
		}
		break;
	case WRITE_WAITING:
		printf("State: WRITE_WAITING\n");
		break;
	}

ret:
	mutex_exit(&pl->lock);
	return error;
} 

/*
 * Device would read only in WRITE_WAITING state and then update the state to 
 * READ_WAITING.
 */ 
int
pollpal_read(file_t *fp, off_t *offset, struct uio *uio, kauth_cred_t cred,
    int flags)
{
	pal_t *pl = fp->f_data;
	int error;
	
	error = 0;
	
	/* To ensure that only single process can read device at a time. */ 
	mutex_enter(&pl->lock);
	cv_broadcast(&pl->sc_cv);
	switch (pl->sc_state) {
	case READ_WAITING:
		printf("State: READ_WAITING\n");
		printf("You need to write something to the module first!\n");
		goto ret;
	case WRITE_WAITING:
		pl->sc_state = READ_WAITING;
		selnotify(&pl->psel, POLLIN | POLLRDNORM, 0);
		while (pl->sc_state == READ_WAITING) {
			if (!pl->buf) {
				error = cv_wait_sig(&pl->sc_cv, &pl->lock);
				if (error)
					goto ret;
				
			}
			printf("The string you entered was: ");
			uiomove(pl->buf, pl->buf_len, uio);
			printf("\n");
			if (check_pal(pl->buf, pl->buf_len))
				printf("String '%s' was a palindrome.\n", 
				    pl->buf);
			else
				printf("String '%s' was not a palindrome.\n", 
				    pl->buf);

			break;
		}
		break;
	} 
	kmem_free(pl->buf, pl->buf_len);
	pl->buf = NULL;

ret:
	mutex_exit(&pl->lock);
	return error;
} 

int 
pollpal_poll(struct file *fp, int events)
{
	pal_t *pl = fp->f_data;
	int revents;
	
	revents = 0;
	
	mutex_enter(&pl->lock);
	switch (pl->sc_state) {
	case READ_WAITING:
		if (events & (POLLOUT | POLLWRNORM)) {
			/* When device is in READ_WAITING state it can write */
			revents |= POLLOUT | POLLWRNORM;
		} else {
			/* Record the request if it wasn't satisfied. */
			selrecord(curlwp, &pl->psel);
		}
		break;
	case WRITE_WAITING:
		if (events && (POLLIN | POLLRDNORM)) {
			/* When device is in WRITE_WAITING state it can read. */
			revents |= POLLIN;
		} else {
			/* Record the request if it wasn't satisfied. */
			selrecord(curlwp, &pl->psel);
		}
		break;
	}

	mutex_exit(&pl->lock);
	return revents;
} 

MODULE(MODULE_CLASS_MISC, pollpal, NULL);

static int
pollpal_modcmd(modcmd_t cmd, void *arg __unused)
{
	int cmajor = 351, bmajor = -1;

	switch (cmd) {
	case MODULE_CMD_INIT:
		if (devsw_attach("pollpal", NULL, &bmajor, &pollpal_cdevsw, 
		    &cmajor))
			return ENXIO;
		return 0;
	case MODULE_CMD_FINI:
		if (pollpal_nopen != 0)
			return EBUSY;
		return devsw_detach(NULL, &pollpal_cdevsw);
	default:
		return ENOTTY;
	} 
}