Re: udev: Why non-blocking poll() with blocking recvmsg()?

Tetsuo Handa <[email protected]>
Newsgroups gmane.linux.hotplug.devel
Message-ID <[email protected]>
Hello Kay.

Kay Sievers wrote:
> > recvmsg() waits until something is queued if udev_monitor->sock is blocking,
> 
> Only on a blocking socket, which it isn't by default:

I confirmed using strace utility that Ubuntu 12.04's wait-for-root
(source code shown below) calls recvmsg() using blocking mode.

  # strace /usr/lib/initramfs-tools/bin/wait-for-root /dev/sdaX 5

> It's from a time where the socket was still blocking, but we still
> used poll() in calling code. We didn't want to block the caller, hence
> the poll() inside the library.

So, "poll() in udev_monitor_receive_device() does not wait" is a feature?

Then, wait-for-root is responsible for retrying the loop (line 91 to 104) when
udev_monitor_receive_device() returned NULL (without waiting for a "block"
subsystem event) caused by udev_monitor_receive_device() getting a non-"block"
subsystem event at recvmsg(), isn't it?

---------- wait-for-root.c start ----------
1:#include <libudev.h>
2:
3:#include <sys/types.h>
4:#include <sys/stat.h>
5:
6:#include <time.h>
7:#include <stdio.h>
8:#include <limits.h>
9:#include <signal.h>
10:#include <stdlib.h>
11:#include <string.h>
12:#include <unistd.h>
13:
14:
15:static int device_queued   (struct udev *udev, const char *path);
16:static int matching_device (struct udev_device *device, const char *path);
17:
18:static void alarm_handler (int signum);
19:
20:
21:int
22:main (int   argc,
23:      char *argv[])
24:{
25:     const char *         devpath;
26:     char                 path[PATH_MAX];
27:     int                  timeout;
28:     struct udev *        udev;
29:     struct udev_monitor *udev_monitor;
30:     struct stat          devstat;
31:     struct udev_device * udev_device;
32:     const char *         type;
33:
34:     if (argc != 3) {
35:             fprintf (stderr, "Usage: %s DEVICE TIMEOUT\n", argv[0]);
36:             exit (2);
37:     }
38:
39:     devpath = argv[1];
40:     if (! strncmp (devpath, "UUID=", 5)) {
41:             strcpy (path, "/dev/disk/by-uuid/");
42:             strcat (path, devpath + 5);
43:     } else if (! strncmp (devpath, "LABEL=", 6)) {
44:             strcpy (path, "/dev/disk/by-label/");
45:             strcat (path, devpath + 6);
46:     } else {
47:             strcpy (path, devpath);
48:     }
49:
50:     timeout = atoi (argv[2]);
51:
52:     signal (SIGALRM, alarm_handler);
53:     alarm (timeout);
54:
55:     /* Connect to the udev monitor first; if we stat() first, the
56:      * event might happen between the stat() and the time we actually
57:      * get hooked up.
58:      */
59:     udev = udev_new ();
60:     udev_monitor = udev_monitor_new_from_netlink (udev, "udev");
61:
62:     udev_monitor_filter_add_match_subsystem_devtype (udev_monitor, "block", NULL);
63:     udev_monitor_enable_receiving (udev_monitor);
64:
65:     /* If the device is not being processed, check to see whether it
66:      * exists already on the filesystem.  If this is true, we don't need
67:      * to wait for it can obtain the filesystem type by looking up the
68:      * udevdb record by major/minor.
69:      */
70:     if ((! device_queued (udev, devpath))
71:         && (stat (path, &devstat) == 0)
72:         && S_ISBLK (devstat.st_mode))
73:     {
74:             udev_device = udev_device_new_from_devnum (udev, 'b', devstat.st_rdev);
75:             if (udev_device) {
76:                     type = udev_device_get_property_value (udev_device, "ID_FS_TYPE");
77:                     if (type) {
78:                             printf ("%s\n", type);
79:
80:                             udev_device_unref (udev_device);
81:                             goto exit;
82:                     }
83:
84:                     udev_device_unref (udev_device);
85:             }
86:     }
87:
88:     /* When the device doesn't exist yet, or is still being processed
89:      * by udev, use the monitor socket to wait it to be done.
90:      */
91:     while ((udev_device = udev_monitor_receive_device (udev_monitor)) != NULL) {
92:             if (matching_device (udev_device, devpath)) {
93:                     type = udev_device_get_property_value (udev_device, "ID_FS_TYPE");
94:                     if (type) {
95:                             printf ("%s\n", type);
96:
97:                             udev_device_unref (udev_device);
98:                             goto exit;
99:                     }
100:
101:            }
102:
103:            udev_device_unref (udev_device);
104:    }
105:
106:exit:
107:    udev_monitor_unref (udev_monitor);
108:    udev_unref (udev);
109:
110:    exit (0);
111:}
112:
113:
114:static int
115:device_queued (struct udev *udev,
116:           const char * devpath)
117:{
118:    struct udev_queue *     udev_queue;
119:    struct udev_list_entry *queue_entry;
120:    int                     found = 0;
121:
122:    udev_queue = udev_queue_new (udev);
123:
124:    for (queue_entry = udev_queue_get_queued_list_entry (udev_queue);
125:         queue_entry != NULL;
126:         queue_entry = udev_list_entry_get_next (queue_entry)) {
127:            const char *        syspath;
128:            struct udev_device *udev_device;
129:
130:            syspath = udev_list_entry_get_name (queue_entry);
131:            udev_device = udev_device_new_from_syspath (udev, syspath);
132:            if (udev_device) {
133:                    if (matching_device (udev_device, devpath))
134:                            found = 1;
135:
136:                    udev_device_unref (udev_device);
137:            }
138:    }
139:
140:    udev_queue_unref (udev_queue);
141:
142:    return found;
143:}
144:
145:static int
146:matching_device (struct udev_device *device,
147:             const char *        path)
148:{
149:    const char *            devnode;
150:    struct udev_list_entry *devlinks_entry;
151:
152:    /* Match by name */
153:    devnode = udev_device_get_devnode (device);
154:    if (devnode && (! strcmp (path, devnode)))
155:            return 1;
156:
157:    /* Match by UUID */
158:    if (! strncmp (path, "UUID=", 5)) {
159:            const char *uuid;
160:
161:            uuid = udev_device_get_property_value (device, "ID_FS_UUID");
162:            if (uuid && (! strcmp (path + 5, uuid)))
163:                    return 1;
164:    }
165:
166:    /* Match by LABEL */
167:    if (! strncmp (path, "LABEL=", 6)) {
168:            const char *label;
169:
170:            label = udev_device_get_property_value (device, "ID_FS_LABEL");
171:            if (label && (! strcmp (path + 6, label)))
172:                    return 1;
173:    }
174:
175:    /* Match by symlink */
176:    for (devlinks_entry = udev_device_get_devlinks_list_entry (device);
177:         devlinks_entry != NULL;
178:         devlinks_entry = udev_list_entry_get_next (devlinks_entry))
179:            if (! strcmp (path, udev_list_entry_get_name (devlinks_entry)))
180:                    return 1;
181:
182:    return 0;
183:}
184:
185:
186:static void
187:alarm_handler (int signum)
188:{
189:    exit (1);
190:}
---------- wait-for-root.c end ----------
--
To unsubscribe from this list: send the line "unsubscribe linux-hotplug" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.