kfusd/kfusd.c
static unsigned int fusd_client_poll(struct file *file, poll_table *wait)
{
	fusd_dev_t *fusd_dev;
	fusd_file_t *fusd_file;
	int kernel_bits = 0;
	int send_poll = 0;

	GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev);
	LOCK_FUSD_FILE(fusd_file);
	LOCK_FUSD_DEV(fusd_dev);

	RDEBUG(3, "got a select on /dev/%s (owned by pid %d) from pid %d, cps=%d",
	       NAME(fusd_dev), fusd_dev->pid, current->pid,
	       fusd_file->cached_poll_state);

	poll_wait(file, &fusd_file->poll_wait, wait);

	/*
	 * If our currently cached poll state is not the same as the
	 * most-recently-sent polldiff request, then, dispatch a new
	 * request.  (We DO NOT wait for a reply, but just dispatch the
	 * request).
	 *
	 * Also, don't send a new polldiff if the most recent one resulted
	 * in an error.
	 */
	if (fusd_file->last_poll_sent != fusd_file->cached_poll_state &&
	    fusd_file->cached_poll_state >= 0) {
		RDEBUG(3, "sending polldiff request because lps=%d, cps=%d",
		       fusd_file->last_poll_sent, fusd_file->cached_poll_state);
		send_poll = 1;
		fusd_file->last_poll_sent = fusd_file->cached_poll_state;
	}

	/* compute what to return for the state we had cached, converting to
	 * bits that have meaning to the kernel */
	if (fusd_file->cached_poll_state > 0) {
		if (fusd_file->cached_poll_state & FUSD_NOTIFY_INPUT)
			kernel_bits |= POLLIN;
		if (fusd_file->cached_poll_state & FUSD_NOTIFY_OUTPUT)
			kernel_bits |= POLLOUT;
		if (fusd_file->cached_poll_state & FUSD_NOTIFY_EXCEPT)
			kernel_bits |= POLLPRI;
	}

	/* Now that we've committed to sending the poll, etc., it should be
	 * safe to unlock the device */
	UNLOCK_FUSD_DEV(fusd_dev);
	UNLOCK_FUSD_FILE(fusd_file);

	if (send_poll) {
		fusd_msg_t fusd_msg;

		init_fusd_msg(&fusd_msg);
		fusd_msg.cmd = FUSD_FOPS_NONBLOCK;
		fusd_msg.subcmd = FUSD_POLL_DIFF;
		fusd_msg.parm.fops_msg.cmd = fusd_file->cached_poll_state;
		if (fusd_fops_call_send(fusd_file, &fusd_msg, NULL) < 0) {
			/* If poll dispatched failed, set back to -1 so we try again.
			 * Not a race (I think), since sending an *extra* polldiff never
			 * hurts anything. */
			fusd_file->last_poll_sent = -1;
		}
	}
	return kernel_bits;

zombie_dev:
	/* might jump here from LOCK_FUSD_DEV */
	UNLOCK_FUSD_FILE(fusd_file);
invalid_dev:
invalid_file:
	RDEBUG(3, "got a select on client file from pid %d, driver has disappeared",
	       current->pid);
	return POLLPRI;
}
/*
 * The design of poll for clients is a bit subtle.
 *
 * We don't want the select() call itself to block, so we keep a cache
 * of the most recently known state supplied by the driver.  The cache
 * is initialized to 0 (meaning: nothing readable/writable).
 *
 * When a poll comes in, we do a non-blocking (!) dispatch of a
 * command telling the driver "This is the state we have cached, reply
 * to this call when the state changes.", and then immediately return
 * the cached state.  We tell the kernel's select to sleep on our
 * poll_wait wait queue.
 *
 * When the driver replies, we update our cached info and wake up the
 * wait queue.  Waking up the wait queue will most likely immediately
 * effect a poll again, in which case we will reply whatever we just
 * cached from the driver.
 * 
 */
The design of poll for clients is a bit subtle.
We don't want the select() call itself to block, so we keep a cache
of the most recently known state supplied by the driver.  The cache
is initialized to 0 (meaning: nothing readable/writable).

When a poll comes in, we do a non-blocking (!) dispatch of a
command telling the driver "This is the state we have cached, reply
to this call when the state changes.", and then immediately return
the cached state.  We tell the kernel's select to sleep on our
poll_wait wait queue.

When the driver replies, we update our cached info and wake up the
wait queue.  Waking up the wait queue will most likely immediately
effect a poll again, in which case we will reply whatever we just
cached from the driver.
The design of poll for clients is a bit subtle . We don ' t want the select () call itself to block so we keep a cache of the most recently known state supplied by the driver . The cache is initialized to 0 ( meaning : nothing readable / writable ) . When a poll comes in we do a non - blocking ( ! ) dispatch of a command telling the driver " This is the state we have cached reply to this call when the state changes . " and then immediately return the cached state . We tell the kernel ' s select to sleep on our poll_wait wait queue . When the driver replies we update our cached info and wake up the wait queue . Waking up the wait queue will most likely immediately effect a poll again in which case we will reply whatever we just cached from the driver .
static unsigned int fusd_client_poll(struct file *file, poll_table *wait)
{
	fusd_dev_t *fusd_dev;
	fusd_file_t *fusd_file;
	int kernel_bits = 0;
	int send_poll = 0;
	GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev);
	LOCK_FUSD_FILE(fusd_file);
	LOCK_FUSD_DEV(fusd_dev);
	RDEBUG(3, "got a select on /dev/%s (owned by pid %d) from pid %d, cps=%d",
	       NAME(fusd_dev), fusd_dev->pid, current->pid,
	       fusd_file->cached_poll_state);
	poll_wait(file, &fusd_file->poll_wait, wait);
	if (fusd_file->last_poll_sent != fusd_file->cached_poll_state &&
	    fusd_file->cached_poll_state >= 0) {
		RDEBUG(3, "sending polldiff request because lps=%d, cps=%d",
		       fusd_file->last_poll_sent, fusd_file->cached_poll_state);
		send_poll = 1;
		fusd_file->last_poll_sent = fusd_file->cached_poll_state;
	}
	if (fusd_file->cached_poll_state > 0) {
		if (fusd_file->cached_poll_state & FUSD_NOTIFY_INPUT)
			kernel_bits |= POLLIN;
		if (fusd_file->cached_poll_state & FUSD_NOTIFY_OUTPUT)
			kernel_bits |= POLLOUT;
		if (fusd_file->cached_poll_state & FUSD_NOTIFY_EXCEPT)
			kernel_bits |= POLLPRI;
	}
	UNLOCK_FUSD_DEV(fusd_dev);
	UNLOCK_FUSD_FILE(fusd_file);
	if (send_poll) {
		fusd_msg_t fusd_msg;
		init_fusd_msg(&fusd_msg);
		fusd_msg.cmd = FUSD_FOPS_NONBLOCK;
		fusd_msg.subcmd = FUSD_POLL_DIFF;
		fusd_msg.parm.fops_msg.cmd = fusd_file->cached_poll_state;
		if (fusd_fops_call_send(fusd_file, &fusd_msg, NULL) < 0) {
			fusd_file->last_poll_sent = -1;
		}
	}
	return kernel_bits;
zombie_dev:
	UNLOCK_FUSD_FILE(fusd_file);
invalid_dev:
invalid_file:
	RDEBUG(3, "got a select on client file from pid %d, driver has disappeared",
	       current->pid);
	return POLLPRI;
}
static unsigned int fusd_client_poll ( struct file * file , poll_table * wait ) { fusd_dev_t * fusd_dev ; fusd_file_t * fusd_file ; int kernel_bits = 0 ; int send_poll = 0 ; GET_FUSD_FILE_AND_DEV ( file -> private_data , fusd_file , fusd_dev ) ; LOCK_FUSD_FILE ( fusd_file ) ; LOCK_FUSD_DEV ( fusd_dev ) ; RDEBUG ( 3 , " " , NAME ( fusd_dev ) , fusd_dev -> pid , current -> pid , fusd_file -> cached_poll_state ) ; poll_wait ( file , & fusd_file -> poll_wait , wait ) ; if ( fusd_file -> last_poll_sent != fusd_file -> cached_poll_state && fusd_file -> cached_poll_state >= 0 ) { RDEBUG ( 3 , " " , fusd_file -> last_poll_sent , fusd_file -> cached_poll_state ) ; send_poll = 1 ; fusd_file -> last_poll_sent = fusd_file -> cached_poll_state ; } if ( fusd_file -> cached_poll_state > 0 ) { if ( fusd_file -> cached_poll_state & FUSD_NOTIFY_INPUT ) kernel_bits |= POLLIN ; if ( fusd_file -> cached_poll_state & FUSD_NOTIFY_OUTPUT ) kernel_bits |= POLLOUT ; if ( fusd_file -> cached_poll_state & FUSD_NOTIFY_EXCEPT ) kernel_bits |= POLLPRI ; } UNLOCK_FUSD_DEV ( fusd_dev ) ; UNLOCK_FUSD_FILE ( fusd_file ) ; if ( send_poll ) { fusd_msg_t fusd_msg ; init_fusd_msg ( & fusd_msg ) ; fusd_msg . cmd = FUSD_FOPS_NONBLOCK ; fusd_msg . subcmd = FUSD_POLL_DIFF ; fusd_msg . parm . fops_msg . cmd = fusd_file -> cached_poll_state ; if ( fusd_fops_call_send ( fusd_file , & fusd_msg , NULL ) < 0 ) { fusd_file -> last_poll_sent = -1 ; } } return kernel_bits ; zombie_dev : UNLOCK_FUSD_FILE ( fusd_file ) ; invalid_dev : invalid_file : RDEBUG ( 3 , " " , current -> pid ) ; return POLLPRI ; }
The design of poll for clients is a bit subtle.
The design of poll for clients is a bit subtle .
/*
	 * If our currently cached poll state is not the same as the
	 * most-recently-sent polldiff request, then, dispatch a new
	 * request.  (We DO NOT wait for a reply, but just dispatch the
	 * request).
	 *
	 * Also, don't send a new polldiff if the most recent one resulted
	 * in an error.
	 */ /* compute what to return for the state we had cached, converting to
	 * bits that have meaning to the kernel */ /* Now that we've committed to sending the poll, etc., it should be
	 * safe to unlock the device */ /* If poll dispatched failed, set back to -1 so we try again.
			 * Not a race (I think), since sending an *extra* polldiff never
			 * hurts anything. */ /* might jump here from LOCK_FUSD_DEV */