Bug 30223

Summary: [patch] Using /usr/share/examples/kld/cdev, testcdev fails when compiled w/ -pthread
Product: Base System Reporter: Rob Phillips <rob>
Component: confAssignee: freebsd-bugs (Nobody) <bugs>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 4.3-STABLE   
Hardware: Any   
OS: Any   

Description Rob Phillips 2001-08-30 20:30:01 UTC
I'm working on writing a KLD device driver that interacts with some
pthread-ed code, and I'm running into problems.  To make sure it wasn't
my code, I took the example code from /usr/share/examples/kld/cdev and
compiled it as-is.  This worked fine.  However, when I added the line:

   COPTS= -pthread

to the Makefile for the testcdev code, it stops working.  The device
driver records a seeminingly infinite loop of write() calls, rather than
the single write call you normally get.  It also records an unknown (to
me) ioctl that isn't there when you don't use threads.

Is this an error with the threads, the device driver, or something else?

How-To-Repeat: Change /usr/share/examples/kld/cdev/test/Makefile to include:

   COPTS= -pthread

It is not necessary to do any changes to the C file.  Recompile and then
run the testcdev program (after loading the cdev driver).
Comment 1 Kip Macy 2002-01-07 04:26:23 UTC
This isn't a bug in the threads library, it is a bug
in the driver :

/*
 * mydev_write takes in a character string and saves it
 * to buf for later accessing.
 */
int
mydev_write(dev_t dev, struct uio *uio, int ioflag)
{
    int err = 0;

    printf("mydev_write: dev_t=%d, uio=%p, ioflag=%d\n",
        dev2udev(dev), uio, ioflag);

    err = copyinstr(uio->uio_iov->iov_base, &buf, 512, &len);
    if (err != 0) {
        printf("Write to \"cdev\" failed.\n");
    }
    return(err);
}

if err is 0 it mydev_write should be returning len, the 
number of bytes copied.

It isn't returning because the thread library does a 
non-blocking write and simulates a blocking write by 
doing writes piecemeal:

                  /*
                   * Loop while no error occurs and until the expected number
                   * of bytes are written if performing a blocking write:
                   */
                  while (ret == 0) {
                          /* Perform a non-blocking write syscall: */
                          n = __sys_write(fd, buf + num, nbytes - num);

sys_write is returning 0 so it keeps on writing the
string over and over again.
write(5,0x804988c,14)                            = 0
(0x0)
poll(0x8059000,0x1,0x0)                          = 1
(0x1)
write(5,0x804988c,14)                            = 0
(0x0)
poll(0x8059000,0x1,0x0)                          = 1
(0x1)

The following patch will make the driver work:
> diff -Naur cdev.c.bak cdev.c
--- cdev.c.bak  Sun Jan  6 18:54:54 2002
+++ cdev.c      Sun Jan  6 20:03:51 2002
@@ -149,16 +149,14 @@
 int
 mydev_write(dev_t dev, struct uio *uio, int ioflag)
 {
-    int err = 0;
+    int towrite = 0;
 
     printf("mydev_write: dev_t=%d, uio=%p, ioflag=%d\n",
        dev2udev(dev), uio, ioflag);
 
-    err = copyinstr(uio->uio_iov->iov_base, &buf, 512, &len);
-    if (err != 0) {
-       printf("Write to \"cdev\" failed.\n");
-    }
-    return(err);
+    towrite = (min(uio->uio_resid, sizeof(buf)));
+    len = towrite;
+    return(uiomove(buf, towrite, uio));
 }
 
 /*

Although the ioctl is still getting called incorrectly
twice when compiled with pthread:
once after open:
open("/dev/cdev",0x2,00)                         = 5
(0x5)
fcntl(0x5,0x3,0x0)                               = 2
(0x2)
fcntl(0x5,0x4,0x6)                              
ERR#22 'Invalid argument'

and once before exit:
fcntl(0x5,0x4,0x2)                              
ERR#22 'Invalid argument'
exit(0x0)                                      
process exit, rval = 0

What is doing is setting the nonblocking flag on open,
and unsetting on exit and this trivial driver doesn't
support having flags set on it:
        /*
         * Enter a loop to set all file descriptors to blocking
         * if they were not created as non-blocking:
         */
        for (i = 0; i < _thread_dtablesize; i++) {
                /* Check if this file descriptor is in use: */
                if (_thread_fd_table[i] != NULL &&
                        !(_thread_fd_table[i]->flags & O_NONBLOCK)) {
                        /* Get the current flags: */
                        flags = _thread_sys_fcntl(i, F_GETFL, NULL);
                        /* Clear the nonblocking file descriptor flag: */
                        _thread_sys_fcntl(i, F_SETFL, flags & ~O_NONBLOCK);
                }
        }

        /* Call the _exit syscall: */
        _thread_sys__exit(status);




__________________________________________________
Do You Yahoo!?
Send FREE video emails in Yahoo! Mail!
http://promo.yahoo.com/videomail/
Comment 2 Remko Lodder freebsd_committer freebsd_triage 2007-03-07 21:19:43 UTC
State Changed
From-To: open->closed

It was mentioned that this was a bug in the kld code itself (from the 
submitter), no feedback after that so I am assuming this was correct. 
Please prove me my mistake if needed...