From: kay.sievers@vrfy.org Date: Tue, 23 Mar 2004 06:22:20 +0000 (-0800) Subject: [PATCH] replace fgets() with mmap() and introduce udev_lib.[hc] X-Git-Tag: 023~32 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=c81b35c08bbd7789883993ea280e0d3772cce440 [PATCH] replace fgets() with mmap() and introduce udev_lib.[hc] Here we replace the various fgets() with a mmap() call for the config file reading, due to the reported performance problems with klibc. Thanks to Patrick's testing, it makes a very small, close to nothing speed gain for libc users, but a 6 times speed increase for klibc users with a 1000 line config file. I've created a udev_lib.[hc] for this and also moved all the generic stuff from udev.h in there and uninlined the functions. --- diff --git a/Makefile b/Makefile index 000918573..0604c1fa0 100644 --- a/Makefile +++ b/Makefile @@ -201,7 +201,8 @@ SYSFS = $(PWD)/libsysfs/sysfs_bus.o \ $(PWD)/libsysfs/sysfs_utils.o \ $(PWD)/libsysfs/dlist.o -OBJS = udev_config.o \ +OBJS = udev_lib.o \ + udev_config.o \ udev-add.o \ udev-remove.o \ udevdb.o \ @@ -211,6 +212,7 @@ OBJS = udev_config.o \ $(TDB) HEADERS = udev.h \ + udev_lib.h \ namedev.h \ udev_version.h \ udev_dbus.h \ @@ -279,7 +281,7 @@ $(TESTER): $(TESTER).o $(OBJS) $(HEADERS) $(LIBC) $(STRIPCMD) $@ $(INFO): $(INFO).o $(OBJS) $(HEADERS) $(LIBC) - $(LD) $(LDFLAGS) -o $@ $(CRT0) udevinfo.o udev_config.o udevdb.o $(SYSFS) $(TDB) $(LIB_OBJS) $(ARCH_LIB_OBJS) + $(LD) $(LDFLAGS) -o $@ $(CRT0) udevinfo.o udev_lib.o udev_config.o udevdb.o $(SYSFS) $(TDB) $(LIB_OBJS) $(ARCH_LIB_OBJS) $(STRIPCMD) $@ $(DAEMON): $(DAEMON).o udevd.h $(LIBC) @@ -287,7 +289,7 @@ $(DAEMON): $(DAEMON).o udevd.h $(LIBC) $(STRIPCMD) $@ $(SENDER): $(SENDER).o udevd.h $(LIBC) - $(LD) $(LDFLAGS) -o $@ $(CRT0) udevsend.o $(LIB_OBJS) $(ARCH_LIB_OBJS) + $(LD) $(LDFLAGS) -o $@ $(CRT0) udevsend.o udev_lib.o $(LIB_OBJS) $(ARCH_LIB_OBJS) $(STRIPCMD) $@ $(STARTER): $(STARTER).o $(HEADERS) $(LIBC) diff --git a/klibc_fixups.c b/klibc_fixups.c index 99460c32f..eaa240c18 100644 --- a/klibc_fixups.c +++ b/klibc_fixups.c @@ -28,6 +28,7 @@ #include #include +#include "udev.h" #include "klibc_fixups.h" #include "logging.h" @@ -40,22 +41,35 @@ static unsigned long get_id_by_name(const char *uname, const char *dbfile) { unsigned long id = -1; - FILE *file; - char buf[255]; + char line[255]; + char *buf; + size_t bufsize; + size_t cur; + size_t count; char *pos; char *name; char *idstr; char *tail; - file = fopen(dbfile, "r"); - if (file == NULL) { - dbg("unable to open file '%s'", dbfile); + if (file_map(dbfile, &buf, &bufsize) == 0) { + dbg("reading '%s' as db file", dbfile); + } else { + dbg("can't open '%s' as db file", dbfile); return -1; } + /* loop through the whole file */ + + cur = 0; while (1) { - pos = fgets(buf, sizeof(buf), file); - if (pos == NULL) + count = buf_get_line(buf, bufsize, cur); + + strncpy(line, buf + cur, count); + line[count] = '\0'; + pos = line; + + cur += count+1; + if (cur > bufsize) break; /* get name */ @@ -82,7 +96,7 @@ static unsigned long get_id_by_name(const char *uname, const char *dbfile) } } - fclose(file); + file_unmap(buf, bufsize); return id; } diff --git a/namedev.c b/namedev.c index 025a14aea..8f781a66e 100644 --- a/namedev.c +++ b/namedev.c @@ -36,6 +36,7 @@ #include "libsysfs/sysfs/libsysfs.h" #include "list.h" #include "udev.h" +#include "udev_lib.h" #include "udev_version.h" #include "logging.h" #include "namedev.h" diff --git a/namedev_parse.c b/namedev_parse.c index 8198f7e68..f4ffdb21d 100644 --- a/namedev_parse.c +++ b/namedev_parse.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -38,6 +37,7 @@ #include #include "udev.h" +#include "udev_lib.h" #include "logging.h" #include "namedev.h" @@ -153,27 +153,36 @@ static int namedev_parse_rules(char *filename) char *temp2; char *temp3; char *attr; - FILE *fd; + char *buf; + size_t bufsize; + size_t cur; + size_t count; int program_given = 0; int retval = 0; struct config_device dev; - fd = fopen(filename, "r"); - if (fd != NULL) { + if (file_map(filename, &buf, &bufsize) == 0) { dbg("reading '%s' as rules file", filename); } else { - dbg("can't open '%s' as a rules file", filename); - return -ENODEV; + dbg("can't open '%s' as rules file", filename); + return -1; } /* loop through the whole file */ + cur = 0; lineno = 0; while (1) { - /* get a line */ - temp = fgets(line, sizeof(line), fd); - if (temp == NULL) - goto exit; + count = buf_get_line(buf, bufsize, cur); + + strncpy(line, buf + cur, count); + line[count] = '\0'; + temp = line; lineno++; + + cur += count+1; + if (cur > bufsize) + break; + dbg_parse("read '%s'", temp); /* eat the whitespace */ @@ -311,8 +320,8 @@ error: filename, lineno, temp - line); } } -exit: - fclose(fd); + + file_unmap(buf, bufsize); return retval; } @@ -321,22 +330,31 @@ static int namedev_parse_permissions(char *filename) char line[255]; char *temp; char *temp2; - FILE *fd; + char *buf; + size_t bufsize; + size_t cur; + size_t count; int retval = 0; struct perm_device dev; - fd = fopen(filename, "r"); - if (fd != NULL) { + if (file_map(filename, &buf, &bufsize) == 0) { dbg("reading '%s' as permissions file", filename); } else { dbg("can't open '%s' as permissions file", filename); - return -ENODEV; + return -1; } /* loop through the whole file */ + cur = 0; while (1) { - temp = fgets(line, sizeof(line), fd); - if (temp == NULL) + count = buf_get_line(buf, bufsize, cur); + + strncpy(line, buf + cur, count); + line[count] = '\0'; + temp = line; + + cur += count+1; + if (cur > bufsize) break; dbg_parse("read '%s'", temp); @@ -394,7 +412,7 @@ static int namedev_parse_permissions(char *filename) } exit: - fclose(fd); + file_unmap(buf, bufsize); return retval; } diff --git a/udev-add.c b/udev-add.c index ce723e45c..2bd16014f 100644 --- a/udev-add.c +++ b/udev-add.c @@ -37,6 +37,7 @@ #include "libsysfs/sysfs/libsysfs.h" #include "udev.h" +#include "udev_lib.h" #include "udev_version.h" #include "udev_dbus.h" #include "udev_selinux.h" diff --git a/udev-remove.c b/udev-remove.c index 44ad603d4..d90971345 100644 --- a/udev-remove.c +++ b/udev-remove.c @@ -29,6 +29,7 @@ #include #include "udev.h" +#include "udev_lib.h" #include "udev_version.h" #include "udev_dbus.h" #include "logging.h" diff --git a/udev.c b/udev.c index 9b4d91f75..d10badc8e 100644 --- a/udev.c +++ b/udev.c @@ -20,15 +20,17 @@ * */ +#include +#include #include #include -#include -#include #include +#include #include #include "libsysfs/sysfs/libsysfs.h" #include "udev.h" +#include "udev_lib.h" #include "udev_version.h" #include "udev_dbus.h" #include "logging.h" diff --git a/udev.h b/udev.h index 8752f595d..54269dfd3 100644 --- a/udev.h +++ b/udev.h @@ -20,25 +20,22 @@ * */ -#ifndef UDEV_H -#define UDEV_H +#ifndef _UDEV_H_ +#define _UDEV_H_ -#include -#include -#include -#include #include +#include "libsysfs/sysfs/libsysfs.h" #define COMMENT_CHARACTER '#' -#define NAME_SIZE 100 -#define OWNER_SIZE 30 -#define GROUP_SIZE 30 -#define MODE_SIZE 8 +#define NAME_SIZE 100 +#define OWNER_SIZE 30 +#define GROUP_SIZE 30 +#define MODE_SIZE 8 -#define ACTION_SIZE 30 -#define DEVPATH_SIZE 255 -#define SUBSYSTEM_SIZE 30 +#define ACTION_SIZE 30 +#define DEVPATH_SIZE 255 +#define SUBSYSTEM_SIZE 30 /* length of public data */ #define UDEVICE_LEN (offsetof(struct udevice, bus_id)) @@ -61,87 +58,6 @@ struct udevice { char kernel_name[NAME_SIZE]; }; -#define strfieldcpy(to, from) \ -do { \ - to[sizeof(to)-1] = '\0'; \ - strncpy(to, from, sizeof(to)-1); \ -} while (0) - -#define strfieldcat(to, from) \ -do { \ - to[sizeof(to)-1] = '\0'; \ - strncat(to, from, sizeof(to) - strlen(to)-1); \ -} while (0) - -#define strfieldcpymax(to, from, maxsize) \ -do { \ - to[maxsize-1] = '\0'; \ - strncpy(to, from, maxsize-1); \ -} while (0) - -#define strfieldcatmax(to, from, maxsize) \ -do { \ - to[maxsize-1] = '\0'; \ - strncat(to, from, maxsize - strlen(to)-1); \ -} while (0) - -#define strintcat(to, i) \ -do { \ - to[sizeof(to)-1] = '\0'; \ - snprintf((to) + strlen(to), sizeof(to) - strlen(to)-1, "%u", i); \ -} while (0) - -#define strintcatmax(to, i, maxsize) \ -do { \ - to[maxsize-1] = '\0'; \ - snprintf((to) + strlen(to), maxsize - strlen(to)-1, "%u", i); \ -} while (0) - -#define foreach_strpart(str, separator, pos, len) \ - for(pos = str, len = 0; \ - (pos) < ((str) + strlen(str)); \ - pos = pos + len + strspn(pos, separator), len = strcspn(pos, separator)) \ - if (len > 0) - -static inline char *get_action(void) -{ - char *action; - - action = getenv("ACTION"); - if (action != NULL && strlen(action) > ACTION_SIZE) - action[ACTION_SIZE-1] = '\0'; - - return action; -} - -static inline char *get_devpath(void) -{ - char *devpath; - - devpath = getenv("DEVPATH"); - if (devpath != NULL && strlen(devpath) > DEVPATH_SIZE) - devpath[DEVPATH_SIZE-1] = '\0'; - - return devpath; -} - -static inline char *get_seqnum(void) -{ - char *seqnum; - - seqnum = getenv("SEQNUM"); - - return seqnum; -} - -static inline char *get_subsystem(char *subsystem) -{ - if (subsystem != NULL && strlen(subsystem) > SUBSYSTEM_SIZE) - subsystem[SUBSYSTEM_SIZE-1] = '\0'; - - return subsystem; -} - extern int udev_add_device(char *path, char *subsystem, int fake); extern int udev_remove_device(char *path, char *subsystem); extern void udev_init_config(void); diff --git a/udev_config.c b/udev_config.c index e2031dc64..57a512d71 100644 --- a/udev_config.c +++ b/udev_config.c @@ -34,6 +34,7 @@ #include "libsysfs/sysfs/libsysfs.h" #include "udev.h" +#include "udev_lib.h" #include "udev_version.h" #include "logging.h" #include "namedev.h" @@ -131,12 +132,14 @@ static int parse_config_file(void) char *temp; char *variable; char *value; - FILE *fd; - int lineno = 0; + char *buf; + size_t bufsize; + size_t cur; + size_t count; + int lineno; int retval = 0; - - fd = fopen(udev_config_filename, "r"); - if (fd != NULL) { + + if (file_map(udev_config_filename, &buf, &bufsize) == 0) { dbg("reading '%s' as config file", udev_config_filename); } else { dbg("can't open '%s' as config file", udev_config_filename); @@ -144,13 +147,20 @@ static int parse_config_file(void) } /* loop through the whole file */ + lineno = 0; + cur = 0; while (1) { - /* get a line */ - temp = fgets(line, sizeof(line), fd); - if (temp == NULL) - goto exit; + count = buf_get_line(buf, bufsize, cur); + + strncpy(line, buf + cur, count); + line[count] = '\0'; + temp = line; lineno++; + cur += count+1; + if (cur > bufsize) + break; + dbg_parse("read '%s'", temp); /* eat the whitespace at the beginning of the line */ @@ -182,8 +192,8 @@ static int parse_config_file(void) } dbg_parse("%s:%d:%Zd: error parsing '%s'", udev_config_filename, lineno, temp - line, temp); -exit: - fclose(fd); + + file_unmap(buf, bufsize); return retval; } diff --git a/udev_lib.c b/udev_lib.c new file mode 100644 index 000000000..50598a4a3 --- /dev/null +++ b/udev_lib.c @@ -0,0 +1,111 @@ +/* + * udev_lib - generic stuff used by udev + * + * Copyright (C) 2004 Kay Sievers + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include +#include +#include +#include +#include +#include + +#include "libsysfs/sysfs/libsysfs.h" +#include "udev.h" +#include "udev_lib.h" + + +char *get_action(void) +{ + char *action; + + action = getenv("ACTION"); + if (action != NULL && strlen(action) > ACTION_SIZE) + action[ACTION_SIZE-1] = '\0'; + + return action; +} + +char *get_devpath(void) +{ + char *devpath; + + devpath = getenv("DEVPATH"); + if (devpath != NULL && strlen(devpath) > DEVPATH_SIZE) + devpath[DEVPATH_SIZE-1] = '\0'; + + return devpath; +} + +char *get_seqnum(void) +{ + char *seqnum; + + seqnum = getenv("SEQNUM"); + + return seqnum; +} + +char *get_subsystem(char *subsystem) +{ + if (subsystem != NULL && strlen(subsystem) > SUBSYSTEM_SIZE) + subsystem[SUBSYSTEM_SIZE-1] = '\0'; + + return subsystem; +} + +int file_map(const char *filename, char **buf, size_t *bufsize) +{ + struct stat stats; + int fd; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + return -1; + } + + if (fstat(fd, &stats) < 0) { + return -1; + } + + *buf = mmap(NULL, stats.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (*buf == MAP_FAILED) { + return -1; + } + *bufsize = stats.st_size; + + close(fd); + + return 0; +} + +void file_unmap(char *buf, size_t bufsize) +{ + munmap(buf, bufsize); +} + +size_t buf_get_line(char *buf, size_t buflen, size_t cur) +{ + size_t count = 0; + + for (count = cur; count < buflen && buf[count] != '\n'; count++); + + return count - cur; +} + diff --git a/udev_lib.h b/udev_lib.h new file mode 100644 index 000000000..565d87e9a --- /dev/null +++ b/udev_lib.h @@ -0,0 +1,78 @@ +/* + * udev_lib - generic stuff used by udev + * + * Copyright (C) 2004 Kay Sievers + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _UDEV_LIB_H_ +#define _UDEV_LIB_H_ + + +#define strfieldcpy(to, from) \ +do { \ + to[sizeof(to)-1] = '\0'; \ + strncpy(to, from, sizeof(to)-1); \ +} while (0) + +#define strfieldcat(to, from) \ +do { \ + to[sizeof(to)-1] = '\0'; \ + strncat(to, from, sizeof(to) - strlen(to)-1); \ +} while (0) + +#define strfieldcpymax(to, from, maxsize) \ +do { \ + to[maxsize-1] = '\0'; \ + strncpy(to, from, maxsize-1); \ +} while (0) + +#define strfieldcatmax(to, from, maxsize) \ +do { \ + to[maxsize-1] = '\0'; \ + strncat(to, from, maxsize - strlen(to)-1); \ +} while (0) + +#define strintcat(to, i) \ +do { \ + to[sizeof(to)-1] = '\0'; \ + snprintf((to) + strlen(to), sizeof(to) - strlen(to)-1, "%u", i); \ +} while (0) + +#define strintcatmax(to, i, maxsize) \ +do { \ + to[maxsize-1] = '\0'; \ + snprintf((to) + strlen(to), maxsize - strlen(to)-1, "%u", i); \ +} while (0) + +#define foreach_strpart(str, separator, pos, len) \ + for(pos = str, len = 0; \ + (pos) < ((str) + strlen(str)); \ + pos = pos + len + strspn(pos, separator), len = strcspn(pos, separator)) \ + if (len > 0) + + +extern char *get_action(void); +extern char *get_devpath(void); +extern char *get_seqnum(void); +extern char *get_subsystem(char *subsystem); +extern int file_map(const char *filename, char **buf, size_t *bufsize); +extern void file_unmap(char *buf, size_t bufsize); +extern size_t buf_get_line(char *buf, size_t buflen, size_t cur); + + +#endif diff --git a/udevd.c b/udevd.c index efcb65bb5..4cb3e1d40 100644 --- a/udevd.c +++ b/udevd.c @@ -36,6 +36,7 @@ #include "list.h" #include "udev.h" +#include "udev_lib.h" #include "udev_version.h" #include "udevd.h" #include "logging.h" diff --git a/udevdb.c b/udevdb.c index 01df3ba7e..40580e5a3 100644 --- a/udevdb.c +++ b/udevdb.c @@ -1,5 +1,5 @@ /* - * udevdb.c + * udevdb.c - udev database library * * Userspace devfs * @@ -21,13 +21,11 @@ * */ -/* - * udev database library - */ #define _KLIBC_HAS_ARCH_SIG_ATOMIC_T #include #include #include +#include #include #include #include @@ -35,8 +33,9 @@ #include #include "libsysfs/sysfs/libsysfs.h" -#include "udev_version.h" #include "udev.h" +#include "udev_lib.h" +#include "udev_version.h" #include "logging.h" #include "namedev.h" #include "udevdb.h" diff --git a/udevinfo.c b/udevinfo.c index ffc5e31f0..5ad9e6474 100644 --- a/udevinfo.c +++ b/udevinfo.c @@ -30,6 +30,7 @@ #include "libsysfs/sysfs/libsysfs.h" #include "libsysfs/dlist.h" #include "udev.h" +#include "udev_lib.h" #include "udev_version.h" #include "logging.h" #include "udevdb.h" diff --git a/udevsend.c b/udevsend.c index 11234808d..f1c46d336 100644 --- a/udevsend.c +++ b/udevsend.c @@ -36,6 +36,7 @@ #include #include "udev.h" +#include "udev_lib.h" #include "udev_version.h" #include "udevd.h" #include "logging.h"