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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Kernel]     [Linux DVB]     [Asterisk Internet PBX]     [DCCP]     [Netdev]     [X.org]     [Util Linux NG]     [Fedora Women]     [ALSA Devel]     [Linux USB]

  Powered by Linux