From 1856a0cdd6280383340ae830a59c640a1c945deb Mon Sep 17 00:00:00 2001 From: gabor Date: Sun, 27 Sep 2009 13:16:38 +0000 Subject: - Add Galician NLS catalog --- lib/libc/nls/Makefile.inc | 1 + lib/libc/nls/gl_ES.ISO8859-1.msg | 249 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 250 insertions(+) create mode 100644 lib/libc/nls/gl_ES.ISO8859-1.msg (limited to 'lib/libc') diff --git a/lib/libc/nls/Makefile.inc b/lib/libc/nls/Makefile.inc index 9e19e85..234c850 100644 --- a/lib/libc/nls/Makefile.inc +++ b/lib/libc/nls/Makefile.inc @@ -20,6 +20,7 @@ NLS+= el_GR.ISO8859-7 NLS+= es_ES.ISO8859-1 NLS+= fi_FI.ISO8859-1 NLS+= fr_FR.ISO8859-1 +NLS+= gl_ES.ISO8859-1 NLS+= hu_HU.ISO8859-2 NLS+= it_IT.ISO8859-15 NLS+= ko_KR.UTF-8 diff --git a/lib/libc/nls/gl_ES.ISO8859-1.msg b/lib/libc/nls/gl_ES.ISO8859-1.msg new file mode 100644 index 0000000..d97615f --- /dev/null +++ b/lib/libc/nls/gl_ES.ISO8859-1.msg @@ -0,0 +1,249 @@ +$ $FreeBSD$ +$ +$ Message catalog for gl_ES.ISO8859-1 locale +$ +$ strerror() support catalog +$ +$set 1 +$ EPERM +1 Operacin non permitida +$ ENOENT +2 Ficheiro ou directorio inexistente +$ ESRCH +3 Proceso inexistente +$ EINTR +4 Chamada do sistema interrompida +$ EIO +5 Erro de Entrada/Sada +$ ENXIO +6 Dispositivo non configurado +$ E2BIG +7 A lista de argumentos demasiado larga +$ ENOEXEC +8 Erro no formato do executable +$ EBADF +9 Descriptor incorrecto de ficheiro +$ ECHILD +10 Non hai procesos fillos +$ EDEADLK +11 Evitouse o bloqueo do recurso +$ ENOMEM +12 Non se puido asignar memoria +$ EACCES +13 Permiso denegado +$ EFAULT +14 Direccin incorrecta +$ ENOTBLK +15 Precsase un dispositivo de bloques +$ EBUSY +16 Dispositivo ocupado +$ EEXIST +17 O ficheiro xa existe +$ EXDEV +18 Enlace entre dispositivos +$ ENODEV +19 Operacin inadecuada para este dispositivo +$ ENOTDIR +20 Non un directorio +$ EISDIR +21 un directorio +$ EINVAL +22 Argumento inadecuado +$ ENFILE +23 Hai demasiados ficheiros abertos no sistema +$ EMFILE +24 Hai demasiados ficheiros abertos +$ ENOTTY +25 ioctl inapropiado para o dispositivo +$ ETXTBSY +26 Ficheiro de texto ocupado +$ EFBIG +27 Ficheiro demasiado grande +$ ENOSPC +28 Non queda espacio libre no dispositivo +$ ESPIPE +29 seek invlido +$ EROFS +30 Sistema de ficheiros de s lectura +$ EMLINK +31 Demasiados enlaces +$ EPIPE +32 Canal (pipe) roto +$ EDOM +33 Argumento numrico fra de rango +$ ERANGE +34 O resultado demasiado grande +$ EAGAIN, EWOULDBLOCK +35 O recurso non est dispoible temporalmente +$ EINPROGRESS +36 Operacin en proceso +$ EALREADY +37 A operacin xa estase executando +$ ENOTSOCK +38 Operacin de socket inaceptable para o dispositivo +$ EDESTADDRREQ +39 Precsase unha direccin de destino +$ EMSGSIZE +40 Mensaxe demasiado largo +$ EPROTOTYPE +41 Tipo malo de protocolo para o socket +$ ENOPROTOOPT +42 Protocolo non dispoible +$ EPROTONOSUPPORT +43 Protocolo non contemplado +$ ESOCKTNOSUPPORT +44 Tipo de socket non contemplado +$ EOPNOTSUPP +45 Operacin non contemplada +$ EPFNOSUPPORT +46 Familia de protocolos non contemplada +$ EAFNOSUPPORT +47 Familia de direcciones non contemplada pola familia de protocolos +$ EADDRINUSE +48 A direccin xa est en uso +$ EADDRNOTAVAIL +49 Non se puido asignar a direccin requerida +$ ENETDOWN +50 A rede non funciona +$ ENETUNREACH +51 Non se puido acceder rede +$ ENETRESET +52 A conexin de rede interrompiuse ao reinicializar +$ ECONNABORTED +53 Conexin perdida por problemas no software +$ ECONNRESET +54 O interlocutor reinicializou a conexin +$ ENOBUFS +55 Non queda espacio no bfer +$ EISCONN +56 O socket xa estaba conectado +$ ENOTCONN +57 O socket non est conectado +$ ESHUTDOWN +58 Non se pode enviar tras a desconexin do socket +$ ETOOMANYREFS +59 Demasiadas referencias: non poden unirse +$ ETIMEDOUT +60 O tempo de conexin expirou +$ ECONNREFUSED +61 Conexin rexeitada +$ ELOOP +62 Demasiados niveles de enlaces simblicos +$ ENAMETOOLONG +63 Nome de ficheiro demasiado largo +$ EHOSTDOWN +64 A mquina est fra de servicio +$ EHOSTUNREACH +65 Non hai ruta ata a mquina +$ ENOTEMPTY +66 Directorio non baleiro +$ EPROCLIM +67 Demasiados procesos +$ EUSERS +68 Demasiados usuarios +$ EDQUOT +69 Cuota de disco sobrepasada +$ ESTALE +70 Descriptor de ficheiro NFS invlido +$ EREMOTE +71 Ruta con demasiados niveles +$ EBADRPC +72 A estructura da RPC mala +$ ERPCMISMATCH +73 A versin da RPC mala +$ EPROGUNAVAIL +74 A RPC non est accesible +$ EPROGMISMATCH +75 Versin mala do programa +$ EPROCUNAVAIL +76 Procedemento malo para o programa +$ ENOLCK +77 Non hai bloqueos dispoibles +$ ENOSYS +78 Funcin non realizada +$ EFTYPE +79 Tipo de ficheiro ou formato inapropiado +$ EAUTH +80 Erro de autenticacin +$ ENEEDAUTH +81 Precsase un autenticador +$ EIDRM +82 Identificador eliminado +$ ENOMSG +83 Non hai mensaxes do tipo desexado +$ EOVERFLOW +84 Valor demasiado grande para se almacenar no tipo desexado +$ ECANCELED +85 Operacin cancelada +$ EILSEQ +86 Secuencia invlida de byte +$ ENOATTR +87 Atributo non encontrado +$ EDOOFUS +88 Erro de programacin +$ +$ strsignal() support catalog +$ +$set 2 +$ SIGHUP +1 Fin de lia (Hangup) +$ SIGINT +2 Interrompido +$ SIGQUIT +3 Terminado +$ SIGILL +4 Instruccin invlida +$ SIGTRAP +5 Trace/BPT trap +$ SIGABRT +6 Abort trap +$ SIGEMT +7 EMT trap +$ SIGFPE +8 Excepcin de coma flotante +$ SIGKILL +9 Matado +$ SIGBUS +10 Erro no bus +$ SIGSEGV +11 Fallo de segmentacin +$ SIGSYS +12 Chamada ao sistema mala +$ SIGPIPE +13 Canal (pipe) roto +$ SIGALRM +14 Alarma do reloxo +$ SIGTERM +15 Terminado +$ SIGURG +16 Condicin urxente de E/S +$ SIGSTOP +17 Detido (sinal) +$ SIGTSTP +18 Detido +$ SIGCONT +19 Continuando +$ SIGCHLD +20 Proceso fillo terminado +$ SIGTTIN +21 Detido (entrada tty) +$ SIGTTOU +22 Detido (sda tty) +$ SIGIO +23 E/S posible +$ SIGXCPU +24 Sobrepasouse o tempo lmite da CPU +$ SIGXFSZ +25 Sobrepasouse o lmite de tamao de ficheiro +$ SIGVTALRM +26 Temporizador virtual caducado +$ SIGPROF +27 Temporizador de perfilacin caducado +$ SIGWINCH +28 Cambios no tamao de xanela +$ SIGINFO +29 Peticin de informacin +$ SIGUSR1 +30 Sinal definida polo usuario no. 1 +$ SIGUSR2 +31 Sinal definida polo usuario no. 2 -- cgit v1.1 From 79f2f8c774b48d4ef62f92d4a09e80af3ceaca7c Mon Sep 17 00:00:00 2001 From: delphij Date: Mon, 28 Sep 2009 16:59:47 +0000 Subject: Add two new fcntls to enable/disable read-ahead: - F_READAHEAD: specify the amount for sequential access. The amount is specified in bytes and is rounded up to nearest block size. - F_RDAHEAD: Darwin compatible version that use 128KB as the sequential access size. A third argument of zero disables the read-ahead behavior. Please note that the read-ahead amount is also constrainted by sysctl variable, vfs.read_max, which may need to be raised in order to better utilize this feature. Thanks Igor Sysoev for proposing the feature and submitting the original version, and kib@ for his valuable comments. Submitted by: Igor Sysoev Reviewed by: kib@ MFC after: 1 month --- lib/libc/sys/fcntl.2 | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/sys/fcntl.2 b/lib/libc/sys/fcntl.2 index a16724c..250cef4 100644 --- a/lib/libc/sys/fcntl.2 +++ b/lib/libc/sys/fcntl.2 @@ -28,7 +28,7 @@ .\" @(#)fcntl.2 8.2 (Berkeley) 1/12/94 .\" $FreeBSD$ .\" -.Dd March 8, 2008 +.Dd September 28, 2009 .Dt FCNTL 2 .Os .Sh NAME @@ -241,6 +241,22 @@ will be interrupted if the signal handler has not specified the .Dv SA_RESTART (see .Xr sigaction 2 ) . +.It Dv F_READAHEAD +Set or clear the read ahead amount for sequential access to the third +argument, +.Fa arg , +which is rounded up to the nearest block size. +A zero value in +.Fa arg +turns off read ahead. +.It Dv F_RDAHEAD +Equivalent to Darwin counterpart which sets read ahead amount of 128KB +when the third argument, +.Fa arg +is non-zero. +A zero value in +.Fa arg +turns off read ahead. .El .Pp When a shared lock has been set on a segment of a file, -- cgit v1.1 From 77c5ec89d56544c5ccf4137d0abb89d782c46e15 Mon Sep 17 00:00:00 2001 From: marcus Date: Thu, 1 Oct 2009 18:23:50 +0000 Subject: Correct the pthread stub prototype for pthread_mutexattr_settype to allow for the type argument. This is known to fix some pthread_mutexattr_settype() invocations, especially when it comes to pulseaudio. Approved by: kib deischen (threads) MFC after: 3 days --- lib/libc/gen/_pthread_stubs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/_pthread_stubs.c b/lib/libc/gen/_pthread_stubs.c index a3e55b0..147235e 100644 --- a/lib/libc/gen/_pthread_stubs.c +++ b/lib/libc/gen/_pthread_stubs.c @@ -222,7 +222,7 @@ STUB_FUNC1(pthread_mutex_trylock, PJT_MUTEX_TRYLOCK, int, void *) STUB_FUNC1(pthread_mutex_unlock, PJT_MUTEX_UNLOCK, int, void *) STUB_FUNC1(pthread_mutexattr_destroy, PJT_MUTEXATTR_DESTROY, int, void *) STUB_FUNC1(pthread_mutexattr_init, PJT_MUTEXATTR_INIT, int, void *) -STUB_FUNC1(pthread_mutexattr_settype, PJT_MUTEXATTR_SETTYPE, int, void *) +STUB_FUNC2(pthread_mutexattr_settype, PJT_MUTEXATTR_SETTYPE, int, void *, int) STUB_FUNC2(pthread_once, PJT_ONCE, int, void *, void *) STUB_FUNC1(pthread_rwlock_destroy, PJT_RWLOCK_DESTROY, int, void *) STUB_FUNC2(pthread_rwlock_init, PJT_RWLOCK_INIT, int, void *, void *) -- cgit v1.1 From beb0df0cdc08eb2f41c970801e05caae7e59c786 Mon Sep 17 00:00:00 2001 From: das Date: Sun, 4 Oct 2009 19:43:36 +0000 Subject: Better glibc compatibility for getline/getdelim: - Tolerate applications that pass a NULL pointer for the buffer and claim that the capacity of the buffer is nonzero. - If an application passes in a non-NULL buffer pointer and claims the buffer has zero capacity, we should free (well, realloc) it anyway. It could have been obtained from malloc(0), so failing to free it would be a small memory leak. MFC After: 2 weeks Reported by: naddy PR: ports/138320 --- lib/libc/stdio/getdelim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdio/getdelim.c b/lib/libc/stdio/getdelim.c index 7af154f..d7d5627 100644 --- a/lib/libc/stdio/getdelim.c +++ b/lib/libc/stdio/getdelim.c @@ -120,8 +120,8 @@ getdelim(char ** __restrict linep, size_t * __restrict linecapp, int delim, goto error; } - if (*linecapp == 0) - *linep = NULL; + if (*linep == NULL) + *linecapp = 0; if (fp->_r <= 0 && __srefill(fp)) { /* If fp is at EOF already, we just need space for the NUL. */ -- cgit v1.1 From 1b3420e9d42bd8cce1889fab5c1da7feb69a036c Mon Sep 17 00:00:00 2001 From: edwin Date: Mon, 5 Oct 2009 07:13:15 +0000 Subject: Modified locale(1) to be able to show the altmon_X fields and the [cxX]_fmt's. Also modify the "-k list" option to display only fields with a certain prefix. MFC after: 1 week --- lib/libc/locale/nl_langinfo.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/locale/nl_langinfo.c b/lib/libc/locale/nl_langinfo.c index 9bd5082..26ca025 100644 --- a/lib/libc/locale/nl_langinfo.c +++ b/lib/libc/locale/nl_langinfo.c @@ -93,6 +93,12 @@ nl_langinfo(nl_item item) case ABMON_9: case ABMON_10: case ABMON_11: case ABMON_12: ret = (char*) __get_current_time_locale()->mon[_REL(ABMON_1)]; break; + case ALTMON_1: case ALTMON_2: case ALTMON_3: case ALTMON_4: + case ALTMON_5: case ALTMON_6: case ALTMON_7: case ALTMON_8: + case ALTMON_9: case ALTMON_10: case ALTMON_11: case ALTMON_12: + ret = (char*) + __get_current_time_locale()->alt_month[_REL(ALTMON_1)]; + break; case ERA: /* XXX: need to be implemented */ ret = ""; -- cgit v1.1 From a71c2bfcab51b8a7e7359a2c1a1a7ba7612bc6d7 Mon Sep 17 00:00:00 2001 From: delphij Date: Mon, 5 Oct 2009 21:11:04 +0000 Subject: fts_open() requires that the list passed as argument to contain at least one path. When the list is empty (contain only a NULL pointer), return EINVAL instead of pretending to succeed, which will cause a NULL pointer deference in a later fts_read() call. Noticed by: Christoph Mallon (via rdivacky@) MFC after: 2 weeks --- lib/libc/gen/fts.3 | 4 ++-- lib/libc/gen/fts.c | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/fts.3 b/lib/libc/gen/fts.3 index 8e1a1e4..dfe2de0 100644 --- a/lib/libc/gen/fts.3 +++ b/lib/libc/gen/fts.3 @@ -28,7 +28,7 @@ .\" @(#)fts.3 8.5 (Berkeley) 4/16/94 .\" $FreeBSD$ .\" -.Dd January 26, 2008 +.Dd October 5, 2009 .Dt FTS 3 .Os .Sh NAME @@ -776,7 +776,7 @@ may fail and set as follows: .Bl -tag -width Er .It Bq Er EINVAL -The options were invalid. +The options were invalid, or the list were empty. .El .Sh SEE ALSO .Xr find 1 , diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c index 41443c5..392bda9 100644 --- a/lib/libc/gen/fts.c +++ b/lib/libc/gen/fts.c @@ -124,6 +124,12 @@ fts_open(argv, options, compar) return (NULL); } + /* fts_open() requires at least one path */ + if (*argv == NULL) { + errno = EINVAL; + return (NULL); + } + /* Allocate/initialize the stream. */ if ((priv = malloc(sizeof(*priv))) == NULL) return (NULL); -- cgit v1.1 From fd2a94971be3ae7d27b361e6a81e7dea97a15966 Mon Sep 17 00:00:00 2001 From: rwatson Date: Tue, 6 Oct 2009 14:05:57 +0000 Subject: Add basename_r(3) to complement basename(3). basename_r(3) which accepts a caller-allocated buffer of at least MAXPATHLEN, rather than using a global buffer. MFC after: 1 month Sponsored by: Google --- lib/libc/gen/Makefile.inc | 1 + lib/libc/gen/Symbol.map | 1 + lib/libc/gen/basename.3 | 20 +++++++++++++++----- lib/libc/gen/basename.c | 24 ++++++++++++++++-------- 4 files changed, 33 insertions(+), 13 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index b06f846..dd9af85 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -76,6 +76,7 @@ MAN+= alarm.3 arc4random.3 \ MLINKS+=arc4random.3 arc4random_addrandom.3 arc4random.3 arc4random_stir.3 \ arc4random.3 arc4random_buf.3 arc4random.3 arc4random_uniform.3 +MLINKS+=basename.3 basename_r.3 MLINKS+=ctermid.3 ctermid_r.3 MLINKS+=devname.3 devname_r.3 MLINKS+=devname.3 fdevname.3 diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index 197430a..6fb61b1 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -367,6 +367,7 @@ FBSD_1.1 { }; FBSD_1.2 { + basename_r; getpagesizes; }; diff --git a/lib/libc/gen/basename.3 b/lib/libc/gen/basename.3 index 33a0a71..4a3743a 100644 --- a/lib/libc/gen/basename.3 +++ b/lib/libc/gen/basename.3 @@ -27,7 +27,7 @@ .\" $OpenBSD: basename.3,v 1.12 2000/04/18 03:01:25 aaron Exp $ .\" $FreeBSD$ .\" -.Dd October 12, 2006 +.Dd October 6, 2009 .Dt BASENAME 3 .Os .Sh NAME @@ -37,6 +37,8 @@ .In libgen.h .Ft char * .Fn basename "const char *path" +.Ft char * +.Fn basename_r "const char *path" "char *bname" .Sh DESCRIPTION The .Fn basename @@ -58,6 +60,12 @@ If is a null pointer or the empty string, a pointer to the string .Qq \&. is returned. +.Pp +The +.Fn basename_r +variation accepts a buffer of at least +.Dv MAXPATHLEN +bytes in which to store the resulting component. .Sh IMPLEMENTATION NOTES The .Fn basename @@ -65,15 +73,17 @@ function returns a pointer to internal storage space allocated on the first call that will be overwritten by subsequent calls. +.Fn basename_r +is therefore preferred for threaded applications. .Sh RETURN VALUES On successful completion, .Fn basename -returns a pointer to the last component of +and +.Fn basename_r +return pointers to the last component of .Fa path . .Pp -If -.Fn basename -fails, a null pointer is returned and the global variable +If they fail, a null pointer is returned and the global variable .Va errno is set to indicate the error. .Sh ERRORS diff --git a/lib/libc/gen/basename.c b/lib/libc/gen/basename.c index 9552ab3..9588c28 100644 --- a/lib/libc/gen/basename.c +++ b/lib/libc/gen/basename.c @@ -40,18 +40,12 @@ __FBSDID("$FreeBSD$"); #include char * -basename(path) +basename_r(path, bname) const char *path; + char *bname; { - static char *bname = NULL; const char *endp, *startp; - if (bname == NULL) { - bname = (char *)malloc(MAXPATHLEN); - if (bname == NULL) - return(NULL); - } - /* Empty or NULL string gets treated as "." */ if (path == NULL || *path == '\0') { (void)strcpy(bname, "."); @@ -82,3 +76,17 @@ basename(path) bname[endp - startp + 1] = '\0'; return(bname); } + +char * +basename(path) + const char *path; +{ + static char *bname = NULL; + + if (bname == NULL) { + bname = (char *)malloc(MAXPATHLEN); + if (bname == NULL) + return (NULL); + } + return (basename_r(path, bname)); +} -- cgit v1.1 From 466473bd42ba80f3f034125e0ef293a188554e34 Mon Sep 17 00:00:00 2001 From: rwatson Date: Wed, 7 Oct 2009 20:20:51 +0000 Subject: Add a new errno, ENOTCAPABLE, to be returned when a process requests an operation on a file descriptor that is not authorized by the descriptor's capability flags. MFC after: 1 month Sponsored by: Google --- lib/libc/gen/errlst.c | 1 + lib/libc/sys/intro.2 | 3 +++ 2 files changed, 4 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/gen/errlst.c b/lib/libc/gen/errlst.c index bc3e0c9..db6bfa2 100644 --- a/lib/libc/gen/errlst.c +++ b/lib/libc/gen/errlst.c @@ -150,5 +150,6 @@ const char *const sys_errlist[] = { "Multihop attempted", /* 90 - EMULTIHOP */ "Link has been severed", /* 91 - ENOLINK */ "Protocol error", /* 92 - EPROTO */ + "Capabilities insufficient", /* 93 - ENOTCAPABLE */ }; const int sys_nerr = sizeof(sys_errlist) / sizeof(sys_errlist[0]); diff --git a/lib/libc/sys/intro.2 b/lib/libc/sys/intro.2 index 1c01c39..b75e52c 100644 --- a/lib/libc/sys/intro.2 +++ b/lib/libc/sys/intro.2 @@ -456,6 +456,9 @@ The specified extended attribute does not exist. .It Er 88 EDOOFUS Em "Programming error" . A function or API is being abused in a way which could only be detected at run-time. +.It Er 93 ENOTCAPABLE Em "Capabilities insufficient" . +An operation on a capability file descriptor requires greater privilege than +the capability allows. .El .Sh DEFINITIONS .Bl -tag -width Ds -- cgit v1.1 From e4ab3f232076f8fad1ffdaf42762ef4355faa7c2 Mon Sep 17 00:00:00 2001 From: das Date: Sun, 11 Oct 2009 00:08:55 +0000 Subject: Document errno codes added in r144530. --- lib/libc/sys/intro.2 | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/sys/intro.2 b/lib/libc/sys/intro.2 index b75e52c..e5ff9df 100644 --- a/lib/libc/sys/intro.2 +++ b/lib/libc/sys/intro.2 @@ -456,6 +456,14 @@ The specified extended attribute does not exist. .It Er 88 EDOOFUS Em "Programming error" . A function or API is being abused in a way which could only be detected at run-time. +.It Er 89 EBADMSG Em "Bad message" . +A corrupted message was detected. +.It Er 90 EMULTIHOP Em "Multihop attempted" . +This error code is unused, but present for compatibility with other systems. +.It Er 91 ENOLINK Em "Link has been severed" . +This error code is unused, but present for compatibility with other systems. +.It Er 92 EPROTO Em "Protocol error" . +A device or socket encountered an unrecoverable protocol error. .It Er 93 ENOTCAPABLE Em "Capabilities insufficient" . An operation on a capability file descriptor requires greater privilege than the capability allows. -- cgit v1.1 From fc266896585f66838536ee5fb80f122f8c10afcb Mon Sep 17 00:00:00 2001 From: kib Date: Sun, 11 Oct 2009 16:23:11 +0000 Subject: In nanosleep(2), note that the calling thread is put to sleep, not the whole process. Also explicitely name the parameter that specifies sleep interval. --- lib/libc/sys/nanosleep.2 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/sys/nanosleep.2 b/lib/libc/sys/nanosleep.2 index 18e4c88..f50544b 100644 --- a/lib/libc/sys/nanosleep.2 +++ b/lib/libc/sys/nanosleep.2 @@ -47,7 +47,9 @@ The .Fn nanosleep system call -causes the process to sleep for the specified time. +causes the calling thread to sleep until the time interval specified by +.Fa rqtp +has elapsed. An unmasked signal will cause it to terminate the sleep early, regardless of the .Dv SA_RESTART -- cgit v1.1 From 874a086f97722040e7f0823d373523c366576960 Mon Sep 17 00:00:00 2001 From: jilles Date: Sun, 11 Oct 2009 20:19:45 +0000 Subject: Make openat(2) a cancellation point. This is required by POSIX and matches open(2). Reviewed by: kib, jhb MFC after: 1 month --- lib/libc/include/namespace.h | 1 + lib/libc/include/un-namespace.h | 1 + lib/libc/sys/Symbol.map | 2 ++ 3 files changed, 4 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/include/namespace.h b/lib/libc/include/namespace.h index a65b929..6ba8bab 100644 --- a/lib/libc/include/namespace.h +++ b/lib/libc/include/namespace.h @@ -80,6 +80,7 @@ #define listen _listen #define nanosleep _nanosleep #define open _open +#define openat _openat #define poll _poll #define pthread_atfork _pthread_atfork #define pthread_attr_destroy _pthread_attr_destroy diff --git a/lib/libc/include/un-namespace.h b/lib/libc/include/un-namespace.h index 6b7f49a..00f0df2 100644 --- a/lib/libc/include/un-namespace.h +++ b/lib/libc/include/un-namespace.h @@ -61,6 +61,7 @@ #undef listen #undef nanosleep #undef open +#undef openat #undef poll #undef pthread_atfork #undef pthread_attr_destroy diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map index 56d8aaa..c834a25 100644 --- a/lib/libc/sys/Symbol.map +++ b/lib/libc/sys/Symbol.map @@ -769,6 +769,8 @@ FBSDprivate_1.0 { __sys_olio_listio; _open; __sys_open; + _openat; + __sys_openat; _pathconf; __sys_pathconf; _pipe; -- cgit v1.1 From 1e0040cfb5c218e082b1d15cdc2589447d18d934 Mon Sep 17 00:00:00 2001 From: rwatson Date: Tue, 13 Oct 2009 17:57:06 +0000 Subject: Add C message catalogue entries for newer errnos: EBADMSG, EMULTIHOP, ENOLINK, EPROTO, ENOTCAPABLE. Submitted by: Alan R. S. Bueno MFC after: 3 days (most) --- lib/libc/nls/C.msg | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/nls/C.msg b/lib/libc/nls/C.msg index aa2c4cc..b25e83f 100644 --- a/lib/libc/nls/C.msg +++ b/lib/libc/nls/C.msg @@ -181,6 +181,16 @@ $ ENOATTR 87 Attribute not found $ EDOOFUS 88 Programming error +$ EBADMSG +89 Bad message +$ EMULTIHOP +90 Multihop attempted +$ ENOLINK +91 Link has been severed +$ EPROTO +92 Protocol error +$ ENOTCAPABLE +93 Capabilities insufficient $ $ strsignal() support catalog $ -- cgit v1.1 From 4fdff21cbb6547c80b57bdc57b4340925039ca59 Mon Sep 17 00:00:00 2001 From: jilles Date: Tue, 13 Oct 2009 20:58:22 +0000 Subject: Make getcwd(3) faster, simpler and more compliant using *at syscalls. It is no longer necessary to construct long paths consisting of repeated "../" which may be slow to process and may exceed PATH_MAX. --- lib/libc/gen/getcwd.c | 63 +++++++++++++++------------------------------------ 1 file changed, 18 insertions(+), 45 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/getcwd.c b/lib/libc/gen/getcwd.c index 0cd3208..c886dde 100644 --- a/lib/libc/gen/getcwd.c +++ b/lib/libc/gen/getcwd.c @@ -62,13 +62,14 @@ getcwd(pt, size) dev_t dev; ino_t ino; int first; - char *bpt, *bup; + char *bpt; struct stat s; dev_t root_dev; ino_t root_ino; - size_t ptsize, upsize; + size_t ptsize; int save_errno; - char *ept, *eup, *up, c; + char *ept, c; + int fd; /* * If no buffer specified by the user, allocate one as necessary. @@ -106,18 +107,6 @@ getcwd(pt, size) bpt = ept - 1; *bpt = '\0'; - /* - * Allocate 1024 bytes for the string of "../"'s. - * Should always be enough. If it's not, allocate - * as necessary. Special case the first stat, it's ".", not "..". - */ - if ((up = malloc(upsize = 1024)) == NULL) - goto err; - eup = up + upsize; - bup = up; - up[0] = '.'; - up[1] = '\0'; - /* Save root values, so know when to stop. */ if (stat("/", &s)) goto err; @@ -128,7 +117,7 @@ getcwd(pt, size) for (first = 1;; first = 0) { /* Stat the current level. */ - if (lstat(up, &s)) + if (dir != NULL ? _fstat(dirfd(dir), &s) : lstat(".", &s)) goto err; /* Save current node values. */ @@ -144,32 +133,22 @@ getcwd(pt, size) * been that way and stuff would probably break. */ bcopy(bpt, pt, ept - bpt); - free(up); + if (dir) + (void) closedir(dir); return (pt); } - /* - * Build pointer to the parent directory, allocating memory - * as necessary. Max length is 3 for "../", the largest - * possible component name, plus a trailing NUL. - */ - while (bup + 3 + MAXNAMLEN + 1 >= eup) { - if ((up = reallocf(up, upsize *= 2)) == NULL) - goto err; - bup = up; - eup = up + upsize; - } - *bup++ = '.'; - *bup++ = '.'; - *bup = '\0'; - /* Open and stat parent directory. */ - if (!(dir = opendir(up)) || _fstat(dirfd(dir), &s)) + fd = _openat(dir != NULL ? dirfd(dir) : AT_FDCWD, + "..", O_RDONLY); + if (fd == -1) goto err; - - /* Add trailing slash for next directory. */ - *bup++ = '/'; - *bup = '\0'; + if (dir) + (void) closedir(dir); + if (!(dir = fdopendir(fd)) || _fstat(dirfd(dir), &s)) { + _close(fd); + goto err; + } /* * If it's a mount point, have to stat each element because @@ -190,10 +169,10 @@ getcwd(pt, size) goto notfound; if (ISDOT(dp)) continue; - bcopy(dp->d_name, bup, dp->d_namlen + 1); /* Save the first error for later. */ - if (lstat(up, &s)) { + if (fstatat(dirfd(dir), dp->d_name, &s, + AT_SYMLINK_NOFOLLOW)) { if (!save_errno) save_errno = errno; errno = 0; @@ -227,11 +206,6 @@ getcwd(pt, size) *--bpt = '/'; bpt -= dp->d_namlen; bcopy(dp->d_name, bpt, dp->d_namlen); - (void) closedir(dir); - dir = NULL; - - /* Truncate any file name. */ - *bup = '\0'; } notfound: @@ -250,7 +224,6 @@ err: free(pt); if (dir) (void) closedir(dir); - free(up); errno = save_errno; return (NULL); -- cgit v1.1 From 2dcc53599c6a7af58c845d0d3796bcde7e21b437 Mon Sep 17 00:00:00 2001 From: jilles Date: Fri, 23 Oct 2009 14:50:11 +0000 Subject: wordexp(3): fix some bugs with signals and long outputs * retry various system calls on EINTR * retry the rest after a short read (common if there is more than about 1K of output) * block SIGCHLD like system(3) does (note that this does not and cannot work fully in threaded programs, they will need to be careful with wait functions) PR: 90580 MFC after: 1 month --- lib/libc/gen/wordexp.c | 76 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 19 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/wordexp.c b/lib/libc/gen/wordexp.c index a437543..06abdc7 100644 --- a/lib/libc/gen/wordexp.c +++ b/lib/libc/gen/wordexp.c @@ -28,8 +28,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -73,6 +75,24 @@ wordexp(const char * __restrict words, wordexp_t * __restrict we, int flags) return (0); } +static size_t +we_read_fully(int fd, char *buffer, size_t len) +{ + size_t done; + ssize_t nread; + + done = 0; + do { + nread = _read(fd, buffer + done, len - done); + if (nread == -1 && errno == EINTR) + continue; + if (nread <= 0) + break; + done += nread; + } while (done != len); + return done; +} + /* * we_askshell -- * Use the `wordexp' /bin/sh builtin function to do most of the work @@ -90,20 +110,31 @@ we_askshell(const char *words, wordexp_t *we, int flags) size_t sofs; /* Offset into we->we_strings */ size_t vofs; /* Offset into we->we_wordv */ pid_t pid; /* Process ID of child */ + pid_t wpid; /* waitpid return value */ int status; /* Child exit status */ + int error; /* Our return value */ + int serrno; /* errno to return */ char *ifs; /* IFS env. var. */ char *np, *p; /* Handy pointers */ char *nstrings; /* Temporary for realloc() */ char **nwv; /* Temporary for realloc() */ + sigset_t newsigblock, oldsigblock; + serrno = errno; if ((ifs = getenv("IFS")) == NULL) ifs = " \t\n"; if (pipe(pdes) < 0) return (WRDE_NOSPACE); /* XXX */ + (void)sigemptyset(&newsigblock); + (void)sigaddset(&newsigblock, SIGCHLD); + (void)_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock); if ((pid = fork()) < 0) { + serrno = errno; _close(pdes[0]); _close(pdes[1]); + (void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); + errno = serrno; return (WRDE_NOSPACE); /* XXX */ } else if (pid == 0) { @@ -114,6 +145,7 @@ we_askshell(const char *words, wordexp_t *we, int flags) int devnull; char *cmd; + (void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); _close(pdes[0]); if (_dup2(pdes[1], STDOUT_FILENO) < 0) _exit(1); @@ -139,10 +171,11 @@ we_askshell(const char *words, wordexp_t *we, int flags) * the expanded words separated by nulls. */ _close(pdes[1]); - if (_read(pdes[0], wbuf, 8) != 8 || _read(pdes[0], bbuf, 8) != 8) { - _close(pdes[0]); - _waitpid(pid, &status, 0); - return (flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX); + if (we_read_fully(pdes[0], wbuf, 8) != 8 || + we_read_fully(pdes[0], bbuf, 8) != 8) { + error = flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX; + serrno = errno; + goto cleanup; } wbuf[8] = bbuf[8] = '\0'; nwords = strtol(wbuf, NULL, 16); @@ -162,33 +195,38 @@ we_askshell(const char *words, wordexp_t *we, int flags) if ((nwv = realloc(we->we_wordv, (we->we_wordc + 1 + (flags & WRDE_DOOFFS ? we->we_offs : 0)) * sizeof(char *))) == NULL) { - _close(pdes[0]); - _waitpid(pid, &status, 0); - return (WRDE_NOSPACE); + error = WRDE_NOSPACE; + goto cleanup; } we->we_wordv = nwv; if ((nstrings = realloc(we->we_strings, we->we_nbytes)) == NULL) { - _close(pdes[0]); - _waitpid(pid, &status, 0); - return (WRDE_NOSPACE); + error = WRDE_NOSPACE; + goto cleanup; } for (i = 0; i < vofs; i++) if (we->we_wordv[i] != NULL) we->we_wordv[i] += nstrings - we->we_strings; we->we_strings = nstrings; - if (_read(pdes[0], we->we_strings + sofs, nbytes) != nbytes) { - _close(pdes[0]); - _waitpid(pid, &status, 0); - return (flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX); + if (we_read_fully(pdes[0], we->we_strings + sofs, nbytes) != nbytes) { + error = flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX; + serrno = errno; + goto cleanup; } - if (_waitpid(pid, &status, 0) < 0 || !WIFEXITED(status) || - WEXITSTATUS(status) != 0) { - _close(pdes[0]); - return (flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX); - } + error = 0; +cleanup: _close(pdes[0]); + do + wpid = _waitpid(pid, &status, 0); + while (wpid < 0 && errno == EINTR); + (void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); + if (error != 0) { + errno = serrno; + return (error); + } + if (wpid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) + return (flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX); /* * Break the null-terminated expanded word strings out into -- cgit v1.1 From 08e50139380f182b37e3e8f5bc7c1319119a4abd Mon Sep 17 00:00:00 2001 From: kib Date: Tue, 27 Oct 2009 10:55:34 +0000 Subject: Current pselect(3) is implemented in usermode and thus vulnerable to well-known race condition, which elimination was the reason for the function appearance in first place. If sigmask supplied as argument to pselect() enables a signal, the signal might be delivered before thread called select(2), causing lost wakeup. Reimplement pselect() in kernel, making change of sigmask and sleep atomic. Since signal shall be delivered to the usermode, but sigmask restored, set TDP_OLDMASK and save old mask in td_oldsigmask. The TDP_OLDMASK should be cleared by ast() in case signal was not gelivered during syscall execution. Reviewed by: davidxu Tested by: pho MFC after: 1 month --- lib/libc/gen/pselect.c | 78 ------------------------------------------------- lib/libc/sys/Symbol.map | 3 ++ 2 files changed, 3 insertions(+), 78 deletions(-) delete mode 100644 lib/libc/gen/pselect.c (limited to 'lib/libc') diff --git a/lib/libc/gen/pselect.c b/lib/libc/gen/pselect.c deleted file mode 100644 index 28066a2..0000000 --- a/lib/libc/gen/pselect.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2000 Massachusetts Institute of Technology - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby - * granted, provided that both the above copyright notice and this - * permission notice appear in all copies, that both the above - * copyright notice and this permission notice appear in all - * supporting documentation, and that the name of M.I.T. not be used - * in advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. M.I.T. makes - * no representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied - * warranty. - * - * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS - * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT - * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "namespace.h" -#include -#include - -#include -#include -#include "un-namespace.h" - -__weak_reference(__pselect, pselect); - -/* - * Emulate the POSIX 1003.1g-2000 `pselect' interface. This is the - * same as the traditional BSD `select' function, except that it uses - * a timespec rather than a timeval, doesn't modify the timeout argument, - * and allows the user to specify a signal mask to apply during the select. - */ -int -__pselect(int count, fd_set * __restrict rfds, fd_set * __restrict wfds, - fd_set * __restrict efds, const struct timespec * __restrict timo, - const sigset_t * __restrict mask) -{ - sigset_t omask; - struct timeval tvtimo, *tvp; - int rv, sverrno; - - if (timo) { - TIMESPEC_TO_TIMEVAL(&tvtimo, timo); - tvp = &tvtimo; - } else - tvp = 0; - - if (mask != 0) { - rv = _sigprocmask(SIG_SETMASK, mask, &omask); - if (rv != 0) - return rv; - } - - rv = _select(count, rfds, wfds, efds, tvp); - if (mask != 0) { - sverrno = errno; - _sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); - errno = sverrno; - } - - return rv; -} diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map index c834a25..ce6f32a 100644 --- a/lib/libc/sys/Symbol.map +++ b/lib/libc/sys/Symbol.map @@ -211,6 +211,7 @@ FBSD_1.0 { posix_openpt; preadv; profil; + pselect; ptrace; pwritev; quotactl; @@ -781,6 +782,8 @@ FBSDprivate_1.0 { __sys_preadv; _profil; __sys_profil; + _pselect; + __sys_pselect; _ptrace; __sys_ptrace; _pwritev; -- cgit v1.1 From d752020360bf2d3f1c22e8993e9270446abd230d Mon Sep 17 00:00:00 2001 From: kib Date: Tue, 27 Oct 2009 10:57:53 +0000 Subject: Commit libc files missed in r198508 --- lib/libc/gen/Makefile.inc | 2 +- lib/libc/gen/Symbol.map | 2 -- lib/libc/gen/pselect.3 | 5 ----- 3 files changed, 1 insertion(+), 8 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index dd9af85..e5ca3fa 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -21,7 +21,7 @@ SRCS+= __getosreldate.c __xuname.c \ initgroups.c isatty.c isinf.c isnan.c jrand48.c lcong48.c \ lockf.c lrand48.c mrand48.c nftw.c nice.c \ nlist.c nrand48.c opendir.c \ - pause.c pmadvise.c popen.c posix_spawn.c pselect.c \ + pause.c pmadvise.c popen.c posix_spawn.c \ psignal.c pw_scan.c pwcache.c \ raise.c readdir.c readpassphrase.c rewinddir.c \ scandir.c seed48.c seekdir.c sem.c semctl.c \ diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index 6fb61b1..a3ea75b 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -223,7 +223,6 @@ FBSD_1.0 { posix_madvise; popen; pclose; - pselect; psignal; raise; readdir; @@ -454,7 +453,6 @@ FBSDprivate_1.0 { __opendir2; __pause; _pause; - __pselect; __pw_scan; /* Used by (at least) libutil */ __raise; _raise; diff --git a/lib/libc/gen/pselect.3 b/lib/libc/gen/pselect.3 index a56a0a8..8e306d6 100644 --- a/lib/libc/gen/pselect.3 +++ b/lib/libc/gen/pselect.3 @@ -88,11 +88,6 @@ for a more detailed discussion of the semantics of this interface, and for macros used to manipulate the .Vt "fd_set" data type. -.Sh IMPLEMENTATION NOTES -The -.Fn pselect -function is implemented in the C library as a wrapper around -.Fn select . .Sh RETURN VALUES The .Fn pselect -- cgit v1.1 From 8d44ea1c45f33329a04b2029f60cc562128d4316 Mon Sep 17 00:00:00 2001 From: kib Date: Wed, 28 Oct 2009 11:14:32 +0000 Subject: Move pselect(3) man page to section 2. Noted by: jhb MFC after: 1 month --- lib/libc/gen/Makefile.inc | 2 +- lib/libc/gen/pselect.3 | 122 ---------------------------------------------- lib/libc/sys/Makefile.inc | 3 +- lib/libc/sys/pselect.2 | 122 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 124 deletions(-) delete mode 100644 lib/libc/gen/pselect.3 create mode 100644 lib/libc/sys/pselect.2 (limited to 'lib/libc') diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index e5ca3fa..0bdee9d 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -62,7 +62,7 @@ MAN+= alarm.3 arc4random.3 \ posix_spawnattr_getpgroup.3 posix_spawnattr_getschedparam.3 \ posix_spawnattr_getschedpolicy.3 posix_spawnattr_init.3 \ posix_spawnattr_getsigdefault.3 posix_spawnattr_getsigmask.3 \ - pselect.3 psignal.3 pwcache.3 \ + psignal.3 pwcache.3 \ raise.3 rand48.3 readpassphrase.3 rfork_thread.3 \ scandir.3 sem_destroy.3 sem_getvalue.3 sem_init.3 \ sem_open.3 sem_post.3 sem_timedwait.3 sem_wait.3 \ diff --git a/lib/libc/gen/pselect.3 b/lib/libc/gen/pselect.3 deleted file mode 100644 index 8e306d6..0000000 --- a/lib/libc/gen/pselect.3 +++ /dev/null @@ -1,122 +0,0 @@ -.\" -.\" Copyright 2002 Massachusetts Institute of Technology -.\" -.\" Permission to use, copy, modify, and distribute this software and -.\" its documentation for any purpose and without fee is hereby -.\" granted, provided that both the above copyright notice and this -.\" permission notice appear in all copies, that both the above -.\" copyright notice and this permission notice appear in all -.\" supporting documentation, and that the name of M.I.T. not be used -.\" in advertising or publicity pertaining to distribution of the -.\" software without specific, written prior permission. M.I.T. makes -.\" no representations about the suitability of this software for any -.\" purpose. It is provided "as is" without express or implied -.\" warranty. -.\" -.\" THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS -.\" ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, -.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT -.\" SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" $FreeBSD$ -.\" -.Dd June 16, 2002 -.Dt PSELECT 3 -.Os -.Sh NAME -.Nm pselect -.Nd synchronous I/O multiplexing a la POSIX.1g -.Sh LIBRARY -.Lb libc -.Sh SYNOPSIS -.In sys/select.h -.Ft int -.Fo pselect -.Fa "int nfds" -.Fa "fd_set * restrict readfds" -.Fa "fd_set * restrict writefds" -.Fa "fd_set * restrict exceptfds" -.Fa "const struct timespec * restrict timeout" -.Fa "const sigset_t * restrict newsigmask" -.Fc -.Sh DESCRIPTION -The -.Fn pselect -function was introduced by -.St -p1003.1g-2000 -as a slightly stronger version of -.Xr select 2 . -The -.Fa nfds , readfds , writefds , -and -.Fa exceptfds -arguments are all identical to the analogous arguments of -.Fn select . -The -.Fa timeout -argument in -.Fn pselect -points to a -.Vt "const struct timespec" -rather than the (modifiable) -.Vt "struct timeval" -used by -.Fn select ; -as in -.Fn select , -a null pointer may be passed to indicate that -.Fn pselect -should wait indefinitely. -Finally, -.Fa newsigmask -specifies a signal mask which is set while waiting for input. -When -.Fn pselect -returns, the original signal mask is restored. -.Pp -See -.Xr select 2 -for a more detailed discussion of the semantics of this interface, and -for macros used to manipulate the -.Vt "fd_set" -data type. -.Sh RETURN VALUES -The -.Fn pselect -function returns the same values and under the same conditions as -.Fn select . -.Sh ERRORS -The -.Fn pselect -function may fail for any of the reasons documented for -.Xr select 2 -and (if a signal mask is provided) -.Xr sigprocmask 2 . -.Sh SEE ALSO -.Xr kqueue 2 , -.Xr poll 2 , -.Xr select 2 , -.Xr sigprocmask 2 -.Sh STANDARDS -The -.Fn pselect -function conforms to -.St -p1003.1-2001 . -.Sh HISTORY -The -.Fn pselect -function first appeared in -.Fx 5.0 . -.Sh AUTHORS -The -.Fn pselect -function and this manual page were written by -.An Garrett Wollman Aq wollman@FreeBSD.org . diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc index 1e6059d..1915c55 100644 --- a/lib/libc/sys/Makefile.inc +++ b/lib/libc/sys/Makefile.inc @@ -83,7 +83,8 @@ MAN+= abort2.2 accept.2 access.2 acct.2 adjtime.2 \ mq_setattr.2 \ msgctl.2 msgget.2 msgrcv.2 msgsnd.2 \ msync.2 munmap.2 nanosleep.2 nfssvc.2 ntp_adjtime.2 open.2 \ - pathconf.2 pipe.2 poll.2 posix_openpt.2 profil.2 ptrace.2 quotactl.2 \ + pathconf.2 pipe.2 poll.2 posix_openpt.2 profil.2 \ + pselect.2 ptrace.2 quotactl.2 \ read.2 readlink.2 reboot.2 recv.2 rename.2 revoke.2 rfork.2 rmdir.2 \ rtprio.2 .if !defined(NO_P1003_1B) diff --git a/lib/libc/sys/pselect.2 b/lib/libc/sys/pselect.2 new file mode 100644 index 0000000..cf784a5 --- /dev/null +++ b/lib/libc/sys/pselect.2 @@ -0,0 +1,122 @@ +.\" +.\" Copyright 2002 Massachusetts Institute of Technology +.\" +.\" Permission to use, copy, modify, and distribute this software and +.\" its documentation for any purpose and without fee is hereby +.\" granted, provided that both the above copyright notice and this +.\" permission notice appear in all copies, that both the above +.\" copyright notice and this permission notice appear in all +.\" supporting documentation, and that the name of M.I.T. not be used +.\" in advertising or publicity pertaining to distribution of the +.\" software without specific, written prior permission. M.I.T. makes +.\" no representations about the suitability of this software for any +.\" purpose. It is provided "as is" without express or implied +.\" warranty. +.\" +.\" THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS +.\" ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, +.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT +.\" SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd October 27, 2009 +.Dt PSELECT 2 +.Os +.Sh NAME +.Nm pselect +.Nd synchronous I/O multiplexing a la POSIX.1g +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/select.h +.Ft int +.Fo pselect +.Fa "int nfds" +.Fa "fd_set * restrict readfds" +.Fa "fd_set * restrict writefds" +.Fa "fd_set * restrict exceptfds" +.Fa "const struct timespec * restrict timeout" +.Fa "const sigset_t * restrict newsigmask" +.Fc +.Sh DESCRIPTION +The +.Fn pselect +function was introduced by +.St -p1003.1g-2000 +as a slightly stronger version of +.Xr select 2 . +The +.Fa nfds , readfds , writefds , +and +.Fa exceptfds +arguments are all identical to the analogous arguments of +.Fn select . +The +.Fa timeout +argument in +.Fn pselect +points to a +.Vt "const struct timespec" +rather than the (modifiable) +.Vt "struct timeval" +used by +.Fn select ; +as in +.Fn select , +a null pointer may be passed to indicate that +.Fn pselect +should wait indefinitely. +Finally, +.Fa newsigmask +specifies a signal mask which is set while waiting for input. +When +.Fn pselect +returns, the original signal mask is restored. +.Pp +See +.Xr select 2 +for a more detailed discussion of the semantics of this interface, and +for macros used to manipulate the +.Vt "fd_set" +data type. +.Sh RETURN VALUES +The +.Fn pselect +function returns the same values and under the same conditions as +.Fn select . +.Sh ERRORS +The +.Fn pselect +function may fail for any of the reasons documented for +.Xr select 2 +and (if a signal mask is provided) +.Xr sigprocmask 2 . +.Sh SEE ALSO +.Xr kqueue 2 , +.Xr poll 2 , +.Xr select 2 , +.Xr sigprocmask 2 +.Sh STANDARDS +The +.Fn pselect +function conforms to +.St -p1003.1-2001 . +.Sh HISTORY +The +.Fn pselect +function first appeared in +.Fx 5.0 . +.Sh AUTHORS +The first implementation of +.Fn pselect +function and this manual page were written by +.An Garrett Wollman Aq wollman@FreeBSD.org . -- cgit v1.1 From 32be6002c2189505febb30d5026202a0eee2ee60 Mon Sep 17 00:00:00 2001 From: cperciva Date: Mon, 2 Nov 2009 07:21:13 +0000 Subject: Attempt to reduce accidental foot-shooting by pointing out that accept(2)ed sockets do not necessarily inherit O_NONBLOCK from listening sockets on non-FreeBSD platforms. Feet shot: cperciva MFC after: 1 month --- lib/libc/sys/accept.2 | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/sys/accept.2 b/lib/libc/sys/accept.2 index 4387dc6..df6c0b1 100644 --- a/lib/libc/sys/accept.2 +++ b/lib/libc/sys/accept.2 @@ -126,6 +126,10 @@ new socket. For some applications, performance may be enhanced by using an .Xr accept_filter 9 to pre-process incoming connections. +.Pp +Portable programs should not rely on the +.Dv O_NONBLOCK +property being inherited. .Sh RETURN VALUES The call returns \-1 on error. If it succeeds, it returns a non-negative -- cgit v1.1 From 8169c493e6774b33d1e4147fb9a5bb60cb38bd90 Mon Sep 17 00:00:00 2001 From: brueffer Date: Mon, 2 Nov 2009 12:35:38 +0000 Subject: Use our canonical .Dd format. Submitted by: Ulrich Spoerlein --- lib/libc/gen/posix_spawn.3 | 2 +- lib/libc/gen/posix_spawn_file_actions_addopen.3 | 2 +- lib/libc/gen/posix_spawn_file_actions_init.3 | 2 +- lib/libc/gen/posix_spawnattr_getflags.3 | 2 +- lib/libc/gen/posix_spawnattr_getpgroup.3 | 2 +- lib/libc/gen/posix_spawnattr_getschedparam.3 | 2 +- lib/libc/gen/posix_spawnattr_getschedpolicy.3 | 2 +- lib/libc/gen/posix_spawnattr_getsigdefault.3 | 2 +- lib/libc/gen/posix_spawnattr_getsigmask.3 | 2 +- lib/libc/gen/posix_spawnattr_init.3 | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/posix_spawn.3 b/lib/libc/gen/posix_spawn.3 index 518be2e..7569239 100644 --- a/lib/libc/gen/posix_spawn.3 +++ b/lib/libc/gen/posix_spawn.3 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd Mar 24, 2008 +.Dd March 24, 2008 .Dt POSIX_SPAWN 3 .Os .Sh NAME diff --git a/lib/libc/gen/posix_spawn_file_actions_addopen.3 b/lib/libc/gen/posix_spawn_file_actions_addopen.3 index b1fc259..c6fd017 100644 --- a/lib/libc/gen/posix_spawn_file_actions_addopen.3 +++ b/lib/libc/gen/posix_spawn_file_actions_addopen.3 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd Mar 24, 2008 +.Dd March 24, 2008 .Dt POSIX_SPAWN_FILE_ACTIONS_ADDOPEN 3 .Os .Sh NAME diff --git a/lib/libc/gen/posix_spawn_file_actions_init.3 b/lib/libc/gen/posix_spawn_file_actions_init.3 index 31b677e..d826b8b 100644 --- a/lib/libc/gen/posix_spawn_file_actions_init.3 +++ b/lib/libc/gen/posix_spawn_file_actions_init.3 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd Mar 24, 2008 +.Dd March 24, 2008 .Dt POSIX_SPAWN_FILE_ACTIONS_INIT 3 .Os .Sh NAME diff --git a/lib/libc/gen/posix_spawnattr_getflags.3 b/lib/libc/gen/posix_spawnattr_getflags.3 index c3f9ee5..a2dda02 100644 --- a/lib/libc/gen/posix_spawnattr_getflags.3 +++ b/lib/libc/gen/posix_spawnattr_getflags.3 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd Mar 24, 2008 +.Dd March 24, 2008 .Dt POSIX_SPAWNATTR_GETFLAGS 3 .Os .Sh NAME diff --git a/lib/libc/gen/posix_spawnattr_getpgroup.3 b/lib/libc/gen/posix_spawnattr_getpgroup.3 index 8ba8142..5cd51d6 100644 --- a/lib/libc/gen/posix_spawnattr_getpgroup.3 +++ b/lib/libc/gen/posix_spawnattr_getpgroup.3 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd Mar 24, 2008 +.Dd March 24, 2008 .Dt POSIX_SPAWNATTR_GETPGROUP 3 .Os .Sh NAME diff --git a/lib/libc/gen/posix_spawnattr_getschedparam.3 b/lib/libc/gen/posix_spawnattr_getschedparam.3 index 59cece8..70009b9 100644 --- a/lib/libc/gen/posix_spawnattr_getschedparam.3 +++ b/lib/libc/gen/posix_spawnattr_getschedparam.3 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd Mar 24, 2008 +.Dd March 24, 2008 .Dt POSIX_SPAWNATTR_GETSCHEDPARAM 3 .Os .Sh NAME diff --git a/lib/libc/gen/posix_spawnattr_getschedpolicy.3 b/lib/libc/gen/posix_spawnattr_getschedpolicy.3 index 158923a..45c1965 100644 --- a/lib/libc/gen/posix_spawnattr_getschedpolicy.3 +++ b/lib/libc/gen/posix_spawnattr_getschedpolicy.3 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd Mar 24, 2008 +.Dd March 24, 2008 .Dt POSIX_SPAWNATTR_GETSCHEDPOLICY 3 .Os .Sh NAME diff --git a/lib/libc/gen/posix_spawnattr_getsigdefault.3 b/lib/libc/gen/posix_spawnattr_getsigdefault.3 index f37992a..9e13c37 100644 --- a/lib/libc/gen/posix_spawnattr_getsigdefault.3 +++ b/lib/libc/gen/posix_spawnattr_getsigdefault.3 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd Mar 24, 2008 +.Dd March 24, 2008 .Dt POSIX_SPAWNATTR_GETSIGDEFAULT 3 .Os .Sh NAME diff --git a/lib/libc/gen/posix_spawnattr_getsigmask.3 b/lib/libc/gen/posix_spawnattr_getsigmask.3 index 44b5c17..5cee7ec 100644 --- a/lib/libc/gen/posix_spawnattr_getsigmask.3 +++ b/lib/libc/gen/posix_spawnattr_getsigmask.3 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd Mar 24, 2008 +.Dd March 24, 2008 .Dt POSIX_SPAWNATTR_GETSIGMASK 3 .Os .Sh NAME diff --git a/lib/libc/gen/posix_spawnattr_init.3 b/lib/libc/gen/posix_spawnattr_init.3 index 7eddc75..66c99cd 100644 --- a/lib/libc/gen/posix_spawnattr_init.3 +++ b/lib/libc/gen/posix_spawnattr_init.3 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd Mar 24, 2008 +.Dd March 24, 2008 .Dt POSIX_SPAWNATTR_INIT 3 .Os .Sh NAME -- cgit v1.1 From b38978f7902a3c12b4e958fa7159e29ea2d39d9a Mon Sep 17 00:00:00 2001 From: ed Date: Fri, 6 Nov 2009 07:17:31 +0000 Subject: Add MAP_ANONYMOUS. Many operating systems also provide MAP_ANONYMOUS. It's not hard to support this ourselves, we'd better add it to make it more likely for applications to work out of the box. Reviewed by: alc (mman.h) --- lib/libc/sys/mmap.2 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/sys/mmap.2 b/lib/libc/sys/mmap.2 index e632748..4849973 100644 --- a/lib/libc/sys/mmap.2 +++ b/lib/libc/sys/mmap.2 @@ -28,7 +28,7 @@ .\" @(#)mmap.2 8.4 (Berkeley) 5/11/95 .\" $FreeBSD$ .\" -.Dd July 26, 2009 +.Dd November 6, 2009 .Dt MMAP 2 .Os .Sh NAME @@ -108,6 +108,10 @@ The argument is ignored. .\".It Dv MAP_FILE .\"Mapped from a regular file or character-special device memory. +.It Dv MAP_ANONYMOUS +This flag is identical to +.Dv MAP_ANON +and is provided for compatibility. .It Dv MAP_FIXED Do not permit the system to select a different address than the one specified. -- cgit v1.1 From 5f89352d0d04e59017ce5f843c8cd79a22077132 Mon Sep 17 00:00:00 2001 From: gabor Date: Sun, 8 Nov 2009 11:32:39 +0000 Subject: - Update Ukranian catalog Submitted by: Alex Kozlov (via private mail) --- lib/libc/nls/uk_UA.UTF-8.msg | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/nls/uk_UA.UTF-8.msg b/lib/libc/nls/uk_UA.UTF-8.msg index e6ea2f77..2b7b02f 100644 --- a/lib/libc/nls/uk_UA.UTF-8.msg +++ b/lib/libc/nls/uk_UA.UTF-8.msg @@ -181,6 +181,16 @@ $ ENOATTR 87 Атрибут не знайдено $ EDOOFUS 88 Помилка програмування +$ EBADMSG +89 Поганий формат повідомлення +$ EMULTIHOP XXX +90 Спроба мултіхопу +$ ENOLINK +91 Мережовий канал розірвано +$ EPROTO +92 Помилка протоколу +$ ENOTCAPABLE +93 Можливості недостатні $ $ strsignal() support catalog $ -- cgit v1.1 From 4968e1f70871dd0da0288d05bcfe2b0c428203e8 Mon Sep 17 00:00:00 2001 From: gabor Date: Sun, 8 Nov 2009 11:55:03 +0000 Subject: - Strip trailing CRs Requested by: Alex Kozlov (via private mail) --- lib/libc/nls/uk_UA.UTF-8.msg | 518 +++++++++++++++++++++---------------------- 1 file changed, 259 insertions(+), 259 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/nls/uk_UA.UTF-8.msg b/lib/libc/nls/uk_UA.UTF-8.msg index 2b7b02f..af871d9 100644 --- a/lib/libc/nls/uk_UA.UTF-8.msg +++ b/lib/libc/nls/uk_UA.UTF-8.msg @@ -1,259 +1,259 @@ -$ $FreeBSD$ -$ -$ Message catalog for uk_UA.UTF-8 locale -$ -$ strerror() support catalog -$ -$set 1 -$ EPERM -1 Операція не дозволена -$ ENOENT -2 Немає такого файлу або каталогу -$ ESRCH -3 Немає такого процесу -$ EINTR -4 Перервано виклик функції -$ EIO -5 Помилка вводу-виводу -$ ENXIO -6 Немає такого пристрою або адреси -$ E2BIG -7 Перелік аргументів надто довгий -$ ENOEXEC -8 Помилка формату виконуваного файлу -$ EBADF -9 Невірний дескриптор файлу -$ ECHILD -10 Немає дочірнього процесу -$ EDEADLK -11 Уникнуто взаємне блокування ресурсів -$ ENOMEM -12 Не достатньо пам'яті -$ EACCES -13 Відмова у доступі -$ EFAULT -14 Невірна адреса -$ ENOTBLK -15 Потрібен блочний пристрій -$ EBUSY -16 Ресурс зайнятий -$ EEXIST -17 Файл вже існує -$ EXDEV -18 Посилання за межі пристрою -$ ENODEV -19 Немає такого пристрою -$ ENOTDIR -20 Це не каталог -$ EISDIR -21 Це каталог -$ EINVAL -22 Недозволений аргумент -$ ENFILE -23 Забагато відкритих файлів у системі -$ EMFILE -24 Забагато відкритих файлів -$ ENOTTY -25 Це не термінал -$ ETXTBSY -26 Текстовий файл зайнятий -$ EFBIG -27 Файл надто великий -$ ENOSPC -28 Не залишилось місця на пристрої -$ ESPIPE -29 Недозволене позиціонування -$ EROFS -30 Файлова система лише для читання -$ EMLINK -31 Забагато посилань -$ EPIPE -32 Канал зруйновано -$ EDOM -33 Помилка області визначення -$ ERANGE -34 Результат надто великий -$ EAGAIN, EWOULDBLOCK -35 Ресурс тимчасово не доступний -$ EINPROGRESS -36 Операція у процесі виконання -$ EALREADY -37 Операція вже виконується -$ ENOTSOCK -38 Це не сокет -$ EDESTADDRREQ -39 Необхідна адреса призначення -$ EMSGSIZE -40 Повідомлення надто довге -$ EPROTOTYPE -41 Помилковий тип протоколу для сокету -$ ENOPROTOOPT -42 Немає такого протоколу -$ EPROTONOSUPPORT -43 Протокол не підтримується -$ ESOCKTNOSUPPORT -44 Цей тип сокету не підтримується -$ EOPNOTSUPP -45 Операція не підтримується -$ EPFNOSUPPORT -46 Родина протоколів не підтримується -$ EAFNOSUPPORT -47 Родина адрес не підтримується протоколом -$ EADDRINUSE -48 Адреса вже використовується -$ EADDRNOTAVAIL -49 Адреса недосяжна -$ ENETDOWN -50 Мережа не працює -$ ENETUNREACH -51 Мережа недосяжна -$ ENETRESET -52 З'єднання припинено мережею -$ ECONNABORTED -53 З'єднання припинено -$ ECONNRESET -54 З'єднання припинено протилежною стороною -$ ENOBUFS -55 Немає вільних буферів -$ EISCONN -56 Сокет вже під'єднано -$ ENOTCONN -57 Сокет не під'єднано -$ ESHUTDOWN -58 Не можу відіслати після закриття сокету протилежною стороною -$ ETOOMANYREFS -59 Забагато посилань: не можу з'єднати -$ ETIMEDOUT -60 Вийшов ліміт часу для з'єднання -$ ECONNREFUSED -61 Відмова у з'єднанні -$ ELOOP -62 Забагато рівнів символічних посилань -$ ENAMETOOLONG -63 Ім'я файлу надто довге -$ EHOSTDOWN -64 Хост не працює -$ EHOSTUNREACH -65 Хост недосяжний -$ ENOTEMPTY -66 Каталог не порожній -$ EPROCLIM -67 Забагато процесів -$ EUSERS -68 Забагато користувачів -$ EDQUOT -69 Перевищена дискова квота -$ ESTALE -70 Застарілий дескриптор файлу NFS -$ EREMOTE -71 Віддалений об'єкт -$ EBADRPC -72 Погана структура RPC -$ ERPCMISMATCH -73 Невірна версія RPC -$ EPROGUNAVAIL -74 Програма RPC недосяжна -$ EPROGMISMATCH -75 Невірна версія програми -$ EPROCUNAVAIL -76 Погана процедура для програми -$ ENOLCK -77 Блокування не доступне -$ ENOSYS -78 Функцію не реалізовано -$ EFTYPE -79 Непридатний тип чи формат файлу -$ EAUTH -80 Помилка аутентифікації -$ ENEEDAUTH -81 Потрібна аутентифікація -$ EIDRM -82 Ідентифікатор вилучено -$ ENOMSG -83 Немає повідомлення бажаного типу -$ EOVERFLOW -84 Завелике значення для цього типу даних -$ ECANCELED -85 Операцію скасовано -$ EILSEQ -86 Недозволена послідовність байтів -$ ENOATTR -87 Атрибут не знайдено -$ EDOOFUS -88 Помилка програмування -$ EBADMSG -89 Поганий формат повідомлення -$ EMULTIHOP XXX -90 Спроба мултіхопу -$ ENOLINK -91 Мережовий канал розірвано -$ EPROTO -92 Помилка протоколу -$ ENOTCAPABLE -93 Можливості недостатні -$ -$ strsignal() support catalog -$ -$set 2 -$ SIGHUP -1 Відключення -$ SIGINT -2 Переривання -$ SIGQUIT -3 Вихід -$ SIGILL -4 Неприпустима інструкція -$ SIGTRAP -5 Пастка трасування -$ SIGABRT -6 Аварійне завершення -$ SIGEMT -7 Перехоплення емульованої інструкції -$ SIGFPE -8 Помилка роботи з плаваючою крапкою -$ SIGKILL -9 Вбито -$ SIGBUS -10 Помилка шини -$ SIGSEGV -11 Порушення сегментації -$ SIGSYS -12 Поганий системний виклик -$ SIGPIPE -13 Канал зруйновано -$ SIGALRM -14 Таймер вичерпано -$ SIGTERM -15 Завершення -$ SIGURG -16 Невідкладний стан на сокеті -$ SIGSTOP -17 Призупинено (сигнал) -$ SIGTSTP -18 Призупинено -$ SIGCONT -19 Продовження роботи -$ SIGCHLD -20 Зміна статусу дочірнього процесу -$ SIGTTIN -21 Зупинено (ввід з терміналу) -$ SIGTTOU -22 Зупинено (вивід на термінал) -$ SIGIO -23 Ввід-вивід можливий -$ SIGXCPU -24 Перевищено ліміт процесорного часу -$ SIGXFSZ -25 Перевищено ліміт максимального розміру файла -$ SIGVTALRM -26 Віртуальний таймер вичерпано -$ SIGPROF -27 Таймер профілювання вичерпано -$ SIGWINCH -28 Розмір вікна змінено -$ SIGINFO -29 Запит інформації -$ SIGUSR1 -30 Сигнал користувача 1 -$ SIGUSR2 -31 Сигнал користувача 2 +$ $FreeBSD$ +$ +$ Message catalog for uk_UA.UTF-8 locale +$ +$ strerror() support catalog +$ +$set 1 +$ EPERM +1 Операція не дозволена +$ ENOENT +2 Немає такого файлу або каталогу +$ ESRCH +3 Немає такого процесу +$ EINTR +4 Перервано виклик функції +$ EIO +5 Помилка вводу-виводу +$ ENXIO +6 Немає такого пристрою або адреси +$ E2BIG +7 Перелік аргументів надто довгий +$ ENOEXEC +8 Помилка формату виконуваного файлу +$ EBADF +9 Невірний дескриптор файлу +$ ECHILD +10 Немає дочірнього процесу +$ EDEADLK +11 Уникнуто взаємне блокування ресурсів +$ ENOMEM +12 Не достатньо пам'яті +$ EACCES +13 Відмова у доступі +$ EFAULT +14 Невірна адреса +$ ENOTBLK +15 Потрібен блочний пристрій +$ EBUSY +16 Ресурс зайнятий +$ EEXIST +17 Файл вже існує +$ EXDEV +18 Посилання за межі пристрою +$ ENODEV +19 Немає такого пристрою +$ ENOTDIR +20 Це не каталог +$ EISDIR +21 Це каталог +$ EINVAL +22 Недозволений аргумент +$ ENFILE +23 Забагато відкритих файлів у системі +$ EMFILE +24 Забагато відкритих файлів +$ ENOTTY +25 Це не термінал +$ ETXTBSY +26 Текстовий файл зайнятий +$ EFBIG +27 Файл надто великий +$ ENOSPC +28 Не залишилось місця на пристрої +$ ESPIPE +29 Недозволене позиціонування +$ EROFS +30 Файлова система лише для читання +$ EMLINK +31 Забагато посилань +$ EPIPE +32 Канал зруйновано +$ EDOM +33 Помилка області визначення +$ ERANGE +34 Результат надто великий +$ EAGAIN, EWOULDBLOCK +35 Ресурс тимчасово не доступний +$ EINPROGRESS +36 Операція у процесі виконання +$ EALREADY +37 Операція вже виконується +$ ENOTSOCK +38 Це не сокет +$ EDESTADDRREQ +39 Необхідна адреса призначення +$ EMSGSIZE +40 Повідомлення надто довге +$ EPROTOTYPE +41 Помилковий тип протоколу для сокету +$ ENOPROTOOPT +42 Немає такого протоколу +$ EPROTONOSUPPORT +43 Протокол не підтримується +$ ESOCKTNOSUPPORT +44 Цей тип сокету не підтримується +$ EOPNOTSUPP +45 Операція не підтримується +$ EPFNOSUPPORT +46 Родина протоколів не підтримується +$ EAFNOSUPPORT +47 Родина адрес не підтримується протоколом +$ EADDRINUSE +48 Адреса вже використовується +$ EADDRNOTAVAIL +49 Адреса недосяжна +$ ENETDOWN +50 Мережа не працює +$ ENETUNREACH +51 Мережа недосяжна +$ ENETRESET +52 З'єднання припинено мережею +$ ECONNABORTED +53 З'єднання припинено +$ ECONNRESET +54 З'єднання припинено протилежною стороною +$ ENOBUFS +55 Немає вільних буферів +$ EISCONN +56 Сокет вже під'єднано +$ ENOTCONN +57 Сокет не під'єднано +$ ESHUTDOWN +58 Не можу відіслати після закриття сокету протилежною стороною +$ ETOOMANYREFS +59 Забагато посилань: не можу з'єднати +$ ETIMEDOUT +60 Вийшов ліміт часу для з'єднання +$ ECONNREFUSED +61 Відмова у з'єднанні +$ ELOOP +62 Забагато рівнів символічних посилань +$ ENAMETOOLONG +63 Ім'я файлу надто довге +$ EHOSTDOWN +64 Хост не працює +$ EHOSTUNREACH +65 Хост недосяжний +$ ENOTEMPTY +66 Каталог не порожній +$ EPROCLIM +67 Забагато процесів +$ EUSERS +68 Забагато користувачів +$ EDQUOT +69 Перевищена дискова квота +$ ESTALE +70 Застарілий дескриптор файлу NFS +$ EREMOTE +71 Віддалений об'єкт +$ EBADRPC +72 Погана структура RPC +$ ERPCMISMATCH +73 Невірна версія RPC +$ EPROGUNAVAIL +74 Програма RPC недосяжна +$ EPROGMISMATCH +75 Невірна версія програми +$ EPROCUNAVAIL +76 Погана процедура для програми +$ ENOLCK +77 Блокування не доступне +$ ENOSYS +78 Функцію не реалізовано +$ EFTYPE +79 Непридатний тип чи формат файлу +$ EAUTH +80 Помилка аутентифікації +$ ENEEDAUTH +81 Потрібна аутентифікація +$ EIDRM +82 Ідентифікатор вилучено +$ ENOMSG +83 Немає повідомлення бажаного типу +$ EOVERFLOW +84 Завелике значення для цього типу даних +$ ECANCELED +85 Операцію скасовано +$ EILSEQ +86 Недозволена послідовність байтів +$ ENOATTR +87 Атрибут не знайдено +$ EDOOFUS +88 Помилка програмування +$ EBADMSG +89 Поганий формат повідомлення +$ EMULTIHOP XXX +90 Спроба мултіхопу +$ ENOLINK +91 Мережовий канал розірвано +$ EPROTO +92 Помилка протоколу +$ ENOTCAPABLE +93 Можливості недостатні +$ +$ strsignal() support catalog +$ +$set 2 +$ SIGHUP +1 Відключення +$ SIGINT +2 Переривання +$ SIGQUIT +3 Вихід +$ SIGILL +4 Неприпустима інструкція +$ SIGTRAP +5 Пастка трасування +$ SIGABRT +6 Аварійне завершення +$ SIGEMT +7 Перехоплення емульованої інструкції +$ SIGFPE +8 Помилка роботи з плаваючою крапкою +$ SIGKILL +9 Вбито +$ SIGBUS +10 Помилка шини +$ SIGSEGV +11 Порушення сегментації +$ SIGSYS +12 Поганий системний виклик +$ SIGPIPE +13 Канал зруйновано +$ SIGALRM +14 Таймер вичерпано +$ SIGTERM +15 Завершення +$ SIGURG +16 Невідкладний стан на сокеті +$ SIGSTOP +17 Призупинено (сигнал) +$ SIGTSTP +18 Призупинено +$ SIGCONT +19 Продовження роботи +$ SIGCHLD +20 Зміна статусу дочірнього процесу +$ SIGTTIN +21 Зупинено (ввід з терміналу) +$ SIGTTOU +22 Зупинено (вивід на термінал) +$ SIGIO +23 Ввід-вивід можливий +$ SIGXCPU +24 Перевищено ліміт процесорного часу +$ SIGXFSZ +25 Перевищено ліміт максимального розміру файла +$ SIGVTALRM +26 Віртуальний таймер вичерпано +$ SIGPROF +27 Таймер профілювання вичерпано +$ SIGWINCH +28 Розмір вікна змінено +$ SIGINFO +29 Запит інформації +$ SIGUSR1 +30 Сигнал користувача 1 +$ SIGUSR2 +31 Сигнал користувача 2 -- cgit v1.1 From 7280a5804337eb23b6b23e35071316756d35365d Mon Sep 17 00:00:00 2001 From: brueffer Date: Sun, 8 Nov 2009 14:02:54 +0000 Subject: Fix a copy+paste error by checking the correct variable against MM_NULLACT. PR: 140386 Submitted by: soulcatcher Date: Mon, 9 Nov 2009 12:28:59 +0000 Subject: Add ja_JP.UTF-8 catalog. Reviewed by: hrs, nork, takawata MFC after: 1 week --- lib/libc/nls/Makefile.inc | 1 + lib/libc/nls/ja_JP.UTF-8.msg | 249 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 250 insertions(+) create mode 100644 lib/libc/nls/ja_JP.UTF-8.msg (limited to 'lib/libc') diff --git a/lib/libc/nls/Makefile.inc b/lib/libc/nls/Makefile.inc index 234c850..9b7148f 100644 --- a/lib/libc/nls/Makefile.inc +++ b/lib/libc/nls/Makefile.inc @@ -23,6 +23,7 @@ NLS+= fr_FR.ISO8859-1 NLS+= gl_ES.ISO8859-1 NLS+= hu_HU.ISO8859-2 NLS+= it_IT.ISO8859-15 +NLS+= ja_JP.UTF-8 NLS+= ko_KR.UTF-8 NLS+= ko_KR.eucKR NLS+= mn_MN.UTF-8 diff --git a/lib/libc/nls/ja_JP.UTF-8.msg b/lib/libc/nls/ja_JP.UTF-8.msg new file mode 100644 index 0000000..940f7b9 --- /dev/null +++ b/lib/libc/nls/ja_JP.UTF-8.msg @@ -0,0 +1,249 @@ +$ $FreeBSD$ +$ +$ Message catalog for C locale (template) +$ +$ strerror() support catalog +$ +$set 1 +$ EPERM +1 許可されていない操作です +$ ENOENT +2 そのようなファイルまたはディレクトリはありません +$ ESRCH +3 そのようなプロセスはありません +$ EINTR +4 システムコールが中断されました +$ EIO +5 入出力エラーです +$ ENXIO +6 デバイスが準備されていません +$ E2BIG +7 引数のリストが長すぎます +$ ENOEXEC +8 無効な実行形式です +$ EBADF +9 無効なファイル記述子です +$ ECHILD +10 子プロセスがありません +$ EDEADLK +11 リソースデッドロックを回避しました +$ ENOMEM +12 メモリの割り当てができません +$ EACCES +13 パーミッションが拒絶されました +$ EFAULT +14 無効なアドレスです +$ ENOTBLK +15 ブロックデバイスが要求されています +$ EBUSY +16 デバイスがビジー状態です +$ EEXIST +17 ファイルが存在します +$ EXDEV +18 デバイスをまたぐリンクです +$ ENODEV +19 デバイスが対応してない操作です +$ ENOTDIR +20 ディレクトリではありません +$ EISDIR +21 ディレクトリです +$ EINVAL +22 無効な引数です +$ ENFILE +23 システム内でオープンされているファイルが多すぎます +$ EMFILE +24 オープンしているファイルが多すぎます +$ ENOTTY +25 デバイスが対応していない ioctl です +$ ETXTBSY +26 テキストファイルがビジー状態です +$ EFBIG +27 ファイルが大きすぎます +$ ENOSPC +28 デバイスの空き領域不足です +$ ESPIPE +29 無効なシークです +$ EROFS +30 読み込み専用ファイルシステムです +$ EMLINK +31 リンク数が多すぎます +$ EPIPE +32 パイプが破壊されてました +$ EDOM +33 数値引数が範囲外です +$ ERANGE +34 結果が大き過ぎます +$ EAGAIN, EWOULDBLOCK +35 リソースが一時的に利用できません +$ EINPROGRESS +36 操作が現在進行中です +$ EALREADY +37 操作は既に進行中です +$ ENOTSOCK +38 ソケットでないものについてソケット操作を行いました +$ EDESTADDRREQ +39 宛先アドレスが要求されています +$ EMSGSIZE +40 メッセージが長すぎます +$ EPROTOTYPE +41 ソケットが対応していないプロトコルタイプです +$ ENOPROTOOPT +42 利用できないプロトコルです +$ EPROTONOSUPPORT +43 対応していないプロトコルです +$ ESOCKTNOSUPPORT +44 対応していないソケットタイプです +$ EOPNOTSUPP +45 対応していない操作です +$ EPFNOSUPPORT +46 対応していないプロトコルファミリです +$ EAFNOSUPPORT +47 プロトコルファミリが対応していないアドレスファミリが指定されました +$ EADDRINUSE +48 アドレスが既に使用中です +$ EADDRNOTAVAIL +49 要求されたアドレスを割り当てできません +$ ENETDOWN +50 ネットワークがダウンしています +$ ENETUNREACH +51 ネットワークに到達できません +$ ENETRESET +52 リセットによりネットワークの接続が失われました +$ ECONNABORTED +53 ソフトウェアによって接続が切断されました +$ ECONNRESET +54 接続が通信相手によってリセットされました +$ ENOBUFS +55 バッファの容量不足です +$ EISCONN +56 ソケットは既に接続されています +$ ENOTCONN +57 ソケットは接続されていません +$ ESHUTDOWN +58 ソケットのシャットダウンの後で送信ができません +$ ETOOMANYREFS +59 処理限界を超える多重参照です +$ ETIMEDOUT +60 操作がタイムアウトしました +$ ECONNREFUSED +61 接続が拒絶されました +$ ELOOP +62 処理限界を超えるシンボリックリンクレベルです +$ ENAMETOOLONG +63 ファイル名が長すぎます +$ EHOSTDOWN +64 ホストがダウンしています +$ EHOSTUNREACH +65 ホストへの経路がありません +$ ENOTEMPTY +66 ディレクトリが空ではありません +$ EPROCLIM +67 プロセスが多すぎます +$ EUSERS +68 ユーザが多すぎます +$ EDQUOT +69 ディスククォータが超過しました +$ ESTALE +70 失効した NFS ファイルハンドルです +$ EREMOTE +71 パス中のリモートのレベルが多すぎます +$ EBADRPC +72 無効な RPC 構造体です +$ ERPCMISMATCH +73 RPC バージョンが間違っています +$ EPROGUNAVAIL +74 RPC プログラムが利用できません +$ EPROGMISMATCH +75 プログラムのバージョンが合っていません +$ EPROCUNAVAIL +76 プログラムでは利用できない procedure です +$ ENOLCK +77 ロックが利用できません +$ ENOSYS +78 関数が実装されていません +$ EFTYPE +79 ファイルの型または形式が不適切です +$ EAUTH +80 認証エラーです +$ ENEEDAUTH +81 認証物が必要です +$ EIDRM +82 識別子は削除されました +$ ENOMSG +83 要求された型のメッセージがありません +$ EOVERFLOW +84 データ型に格納するには大きすぎる値です +$ ECANCELED +85 処理がキャンセルされました +$ EILSEQ +86 不正なバイト列です +$ ENOATTR +87 そのような属性はありません +$ EDOOFUS +88 プログラミングエラーです +$ +$ strsignal() support catalog +$ +$set 2 +$ SIGHUP +1 ハングアップ +$ SIGINT +2 割り込み +$ SIGQUIT +3 中断 +$ SIGILL +4 不正命令 +$ SIGTRAP +5 トレース/BPT トラップ +$ SIGABRT +6 アボートトラップ +$ SIGEMT +7 EMT トラップ +$ SIGFPE +8 浮動小数点例外 +$ SIGKILL +9 Kill された +$ SIGBUS +10 バスエラー +$ SIGSEGV +11 セグメンテーション違反 +$ SIGSYS +12 存在しないシステムコール +$ SIGPIPE +13 パイプ破壊 +$ SIGALRM +14 アラームクロック +$ SIGTERM +15 終了 +$ SIGURG +16 緊急入出力状況 +$ SIGSTOP +17 一時停止 (シグナル) +$ SIGTSTP +18 一時停止 +$ SIGCONT +19 継続 +$ SIGCHLD +20 子プロセスの終了 +$ SIGTTIN +21 一時停止 (tty 入力) +$ SIGTTOU +22 一時停止 (tty 出力) +$ SIGIO +23 入出力可能 +$ SIGXCPU +24 CPU 時間の制限超過 +$ SIGXFSZ +25 ファイルサイズの制限超過 +$ SIGVTALRM +26 仮想タイマの期限超過 +$ SIGPROF +27 プロファイルタイマの期限超過 +$ SIGWINCH +28 ウィンドウサイズの変化 +$ SIGINFO +29 情報要求 +$ SIGUSR1 +30 ユーザ定義シグナル 1 +$ SIGUSR2 +31 ユーザ定義シグナル 2 -- cgit v1.1 From 2a01fbc91102c935f267aa8760303ef318307170 Mon Sep 17 00:00:00 2001 From: ume Date: Mon, 9 Nov 2009 12:33:47 +0000 Subject: Add ja_JP.eucJP catalog. Reviewed by: hrs, nork, takawata MFC after: 1 week --- lib/libc/nls/Makefile.inc | 1 + lib/libc/nls/ja_JP.eucJP.msg | 249 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 250 insertions(+) create mode 100644 lib/libc/nls/ja_JP.eucJP.msg (limited to 'lib/libc') diff --git a/lib/libc/nls/Makefile.inc b/lib/libc/nls/Makefile.inc index 9b7148f..f5c6885 100644 --- a/lib/libc/nls/Makefile.inc +++ b/lib/libc/nls/Makefile.inc @@ -24,6 +24,7 @@ NLS+= gl_ES.ISO8859-1 NLS+= hu_HU.ISO8859-2 NLS+= it_IT.ISO8859-15 NLS+= ja_JP.UTF-8 +NLS+= ja_JP.eucJP NLS+= ko_KR.UTF-8 NLS+= ko_KR.eucKR NLS+= mn_MN.UTF-8 diff --git a/lib/libc/nls/ja_JP.eucJP.msg b/lib/libc/nls/ja_JP.eucJP.msg new file mode 100644 index 0000000..194016d --- /dev/null +++ b/lib/libc/nls/ja_JP.eucJP.msg @@ -0,0 +1,249 @@ +$ $FreeBSD$ +$ +$ Message catalog for C locale (template) +$ +$ strerror() support catalog +$ +$set 1 +$ EPERM +1 ĤƤʤǤ +$ ENOENT +2 Τ褦ʥեޤϥǥ쥯ȥϤޤ +$ ESRCH +3 Τ褦ʥץϤޤ +$ EINTR +4 ƥॳ뤬Ǥޤ +$ EIO +5 ϥ顼Ǥ +$ ENXIO +6 ǥХƤޤ +$ E2BIG +7 ΥꥹȤĹޤ +$ ENOEXEC +8 ̵ʼ¹ԷǤ +$ EBADF +9 ̵ʥե뵭һҤǤ +$ ECHILD +10 ҥץޤ +$ EDEADLK +11 ꥽ǥåɥå򤷤ޤ +$ ENOMEM +12 γƤǤޤ +$ EACCES +13 ѡߥå󤬵䤵ޤ +$ EFAULT +14 ̵ʥɥ쥹Ǥ +$ ENOTBLK +15 ֥åǥХ׵ᤵƤޤ +$ EBUSY +16 ǥХӥ֤Ǥ +$ EEXIST +17 ե뤬¸ߤޤ +$ EXDEV +18 ǥХޤ󥯤Ǥ +$ ENODEV +19 ǥХбƤʤǤ +$ ENOTDIR +20 ǥ쥯ȥǤϤޤ +$ EISDIR +21 ǥ쥯ȥǤ +$ EINVAL +22 ̵ʰǤ +$ ENFILE +23 ƥǥץ󤵤Ƥե뤬¿ޤ +$ EMFILE +24 ץ󤷤Ƥե뤬¿ޤ +$ ENOTTY +25 ǥХбƤʤ ioctl Ǥ +$ ETXTBSY +26 ƥȥե뤬ӥ֤Ǥ +$ EFBIG +27 ե뤬礭ޤ +$ ENOSPC +28 ǥХζΰ­Ǥ +$ ESPIPE +29 ̵ʥǤ +$ EROFS +30 ɤ߹ѥե륷ƥǤ +$ EMLINK +31 󥯿¿ޤ +$ EPIPE +32 ѥפ˲Ƥޤ +$ EDOM +33 ͰϰϳǤ +$ ERANGE +34 ̤礭᤮ޤ +$ EAGAIN, EWOULDBLOCK +35 ꥽ŪѤǤޤ +$ EINPROGRESS +36 ߿ʹǤ +$ EALREADY +37 ϴ˿ʹǤ +$ ENOTSOCK +38 åȤǤʤΤˤĤƥåԤޤ +$ EDESTADDRREQ +39 襢ɥ쥹׵ᤵƤޤ +$ EMSGSIZE +40 åĹޤ +$ EPROTOTYPE +41 åȤбƤʤץȥ륿פǤ +$ ENOPROTOOPT +42 ѤǤʤץȥǤ +$ EPROTONOSUPPORT +43 бƤʤץȥǤ +$ ESOCKTNOSUPPORT +44 бƤʤåȥפǤ +$ EOPNOTSUPP +45 бƤʤǤ +$ EPFNOSUPPORT +46 бƤʤץȥեߥǤ +$ EAFNOSUPPORT +47 ץȥեߥ꤬бƤʤɥ쥹եߥ꤬ꤵޤ +$ EADDRINUSE +48 ɥ쥹˻Ǥ +$ EADDRNOTAVAIL +49 ׵ᤵ줿ɥ쥹ƤǤޤ +$ ENETDOWN +50 ͥåȥ󤷤Ƥޤ +$ ENETUNREACH +51 ͥåȥãǤޤ +$ ENETRESET +52 ꥻåȤˤͥåȥ³ޤ +$ ECONNABORTED +53 եȥˤä³Ǥޤ +$ ECONNRESET +54 ³̿ˤäƥꥻåȤޤ +$ ENOBUFS +55 Хåե­Ǥ +$ EISCONN +56 åȤϴ³Ƥޤ +$ ENOTCONN +57 åȤ³Ƥޤ +$ ESHUTDOWN +58 åȤΥåȥθǤޤ +$ ETOOMANYREFS +59 ³Ķ¿ŻȤǤ +$ ETIMEDOUT +60 ॢȤޤ +$ ECONNREFUSED +61 ³䤵ޤ +$ ELOOP +62 ³Ķ륷ܥå󥯥٥Ǥ +$ ENAMETOOLONG +63 ե̾Ĺޤ +$ EHOSTDOWN +64 ۥȤ󤷤Ƥޤ +$ EHOSTUNREACH +65 ۥȤؤηϩޤ +$ ENOTEMPTY +66 ǥ쥯ȥ꤬ǤϤޤ +$ EPROCLIM +67 ץ¿ޤ +$ EUSERS +68 桼¿ޤ +$ EDQUOT +69 ǥĶᤷޤ +$ ESTALE +70 NFS եϥɥǤ +$ EREMOTE +71 ѥΥ⡼ȤΥ٥뤬¿ޤ +$ EBADRPC +72 ̵ RPC ¤ΤǤ +$ ERPCMISMATCH +73 RPC С󤬴ְäƤޤ +$ EPROGUNAVAIL +74 RPC ץबѤǤޤ +$ EPROGMISMATCH +75 ץΥС󤬹äƤޤ +$ EPROCUNAVAIL +76 ץǤѤǤʤ procedure Ǥ +$ ENOLCK +77 åѤǤޤ +$ ENOSYS +78 ؿƤޤ +$ EFTYPE +79 եηޤϷŬڤǤ +$ EAUTH +80 ǧڥ顼Ǥ +$ ENEEDAUTH +81 ǧʪɬפǤ +$ EIDRM +82 ̻ҤϺޤ +$ ENOMSG +83 ׵ᤵ줿Υåޤ +$ EOVERFLOW +84 ǡ˳Ǽˤ礭ͤǤ +$ ECANCELED +85 󥻥뤵ޤ +$ EILSEQ +86 ʥХǤ +$ ENOATTR +87 Τ褦°Ϥޤ +$ EDOOFUS +88 ץߥ󥰥顼Ǥ +$ +$ strsignal() support catalog +$ +$set 2 +$ SIGHUP +1 ϥ󥰥å +$ SIGINT +2 +$ SIGQUIT +3 +$ SIGILL +4 ̿ +$ SIGTRAP +5 ȥ졼/BPT ȥå +$ SIGABRT +6 ܡȥȥå +$ SIGEMT +7 EMT ȥå +$ SIGFPE +8 ư㳰 +$ SIGKILL +9 Kill 줿 +$ SIGBUS +10 Х顼 +$ SIGSEGV +11 ơȿ +$ SIGSYS +12 ¸ߤʤƥॳ +$ SIGPIPE +13 ѥ˲ +$ SIGALRM +14 顼९å +$ SIGTERM +15 λ +$ SIGURG +16 ۵Ͼ +$ SIGSTOP +17 (ʥ) +$ SIGTSTP +18 +$ SIGCONT +19 ³ +$ SIGCHLD +20 ҥץνλ +$ SIGTTIN +21 (tty ) +$ SIGTTOU +22 (tty ) +$ SIGIO +23 ϲǽ +$ SIGXCPU +24 CPU ֤Ķ +$ SIGXFSZ +25 ե륵Ķ +$ SIGVTALRM +26 ۥޤδĶ +$ SIGPROF +27 ץե륿ޤδĶ +$ SIGWINCH +28 ɥѲ +$ SIGINFO +29 ׵ +$ SIGUSR1 +30 桼ʥ 1 +$ SIGUSR2 +31 桼ʥ 2 -- cgit v1.1 From 916f88dc5a30d26b53dcd17f3f9e551bcba53e05 Mon Sep 17 00:00:00 2001 From: ume Date: Mon, 9 Nov 2009 12:38:13 +0000 Subject: Fix comment. Pointed out by: nyan MFC after: 1 week --- lib/libc/nls/ja_JP.UTF-8.msg | 2 +- lib/libc/nls/ja_JP.eucJP.msg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/nls/ja_JP.UTF-8.msg b/lib/libc/nls/ja_JP.UTF-8.msg index 940f7b9..9ee98d1 100644 --- a/lib/libc/nls/ja_JP.UTF-8.msg +++ b/lib/libc/nls/ja_JP.UTF-8.msg @@ -1,6 +1,6 @@ $ $FreeBSD$ $ -$ Message catalog for C locale (template) +$ Message catalog for ja_JP.UTF-8 locale $ $ strerror() support catalog $ diff --git a/lib/libc/nls/ja_JP.eucJP.msg b/lib/libc/nls/ja_JP.eucJP.msg index 194016d..cba0157 100644 --- a/lib/libc/nls/ja_JP.eucJP.msg +++ b/lib/libc/nls/ja_JP.eucJP.msg @@ -1,6 +1,6 @@ $ $FreeBSD$ $ -$ Message catalog for C locale (template) +$ Message catalog for ja_JP.eucJP locale $ $ strerror() support catalog $ -- cgit v1.1 From a9dc4dbb6208ebff265d4470aa4d32abe2907222 Mon Sep 17 00:00:00 2001 From: ume Date: Mon, 9 Nov 2009 12:46:59 +0000 Subject: Add NLS catalogs support to gai_strerror(3). Controlled by NLS define. --- lib/libc/net/gai_strerror.c | 58 +++++++++++++++++++++++++++++++++++++++++++++ lib/libc/nls/C.msg | 36 ++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/net/gai_strerror.c b/lib/libc/net/gai_strerror.c index 5611559..4f60f2d 100644 --- a/lib/libc/net/gai_strerror.c +++ b/lib/libc/net/gai_strerror.c @@ -30,7 +30,17 @@ #include __FBSDID("$FreeBSD$"); +#include "namespace.h" #include +#if defined(NLS) +#include +#include +#include +#include +#include +#include "reentrant.h" +#endif +#include "un-namespace.h" /* Entries EAI_ADDRFAMILY (1) and EAI_NODATA (7) are obsoleted, but left */ /* for backward compatibility with userland code prior to 2553bis-02 */ @@ -52,9 +62,57 @@ static const char *ai_errlist[] = { "Argument buffer overflow" /* EAI_OVERFLOW */ }; +#if defined(NLS) +static char gai_buf[NL_TEXTMAX]; +static once_t gai_init_once = ONCE_INITIALIZER; +static thread_key_t gai_key; +static int gai_keycreated = 0; + +static void +gai_keycreate(void) +{ + gai_keycreated = (thr_keycreate(&gai_key, free) == 0); +} +#endif + const char * gai_strerror(int ecode) { +#if defined(NLS) + nl_catd catd; + char *buf; + + if (thr_main() != 0) + buf = gai_buf; + else { + if (thr_once(&gai_init_once, gai_keycreate) != 0 || + !gai_keycreated) + goto thr_err; + if ((buf = thr_getspecific(gai_key)) == NULL) { + if ((buf = malloc(sizeof(gai_buf))) == NULL) + goto thr_err; + if (thr_setspecific(gai_key, buf) != 0) { + free(buf); + goto thr_err; + } + } + } + + catd = catopen("libc", NL_CAT_LOCALE); + if (ecode > 0 && ecode < EAI_MAX) + strlcpy(buf, catgets(catd, 3, ecode, ai_errlist[ecode]), + sizeof(gai_buf)); + else if (ecode == 0) + strlcpy(buf, catgets(catd, 3, NL_MSGMAX - 1, "Success"), + sizeof(gai_buf)); + else + strlcpy(buf, catgets(catd, 3, NL_MSGMAX, "Unknown error"), + sizeof(gai_buf)); + catclose(catd); + return buf; + +thr_err: +#endif if (ecode >= 0 && ecode < EAI_MAX) return ai_errlist[ecode]; return "Unknown error"; diff --git a/lib/libc/nls/C.msg b/lib/libc/nls/C.msg index b25e83f..2210df6 100644 --- a/lib/libc/nls/C.msg +++ b/lib/libc/nls/C.msg @@ -257,3 +257,39 @@ $ SIGUSR1 30 User defined signal 1 $ SIGUSR2 31 User defined signal 2 +$ +$ gai_strerror() support catalog +$ +$set 3 +$ 1 (obsolete) +1 Address family for hostname not supported +$ EAI_AGAIN +2 Temporary failure in name resolution +$ EAI_BADFLAGS +3 Invalid value for ai_flags +$ EAI_FAIL +4 Non-recoverable failure in name resolution +$ EAI_FAMILY +5 ai_family not supported +$ EAI_MEMORY +6 Memory allocation failure +$ 7 (obsolete) +7 No address associated with hostname +$ EAI_NONAME +8 hostname nor servname provided, or not known +$ EAI_SERVICE +9 servname not supported for ai_socktype +$ EAI_SOCKTYPE +10 ai_socktype not supported +$ EAI_SYSTEM +11 System error returned in errno +$ EAI_BADHINTS +12 Invalid value for hints +$ EAI_PROTOCOL +13 Resolved protocol is unknown +$ EAI_OVERFLOW +14 Argument buffer overflow +$ 0 +32766 Success +$ NL_MSGMAX +32767 Unknown error -- cgit v1.1 From d70e2a3aeb5315097233a141558b0d283311e0c5 Mon Sep 17 00:00:00 2001 From: ume Date: Mon, 9 Nov 2009 17:26:16 +0000 Subject: Add gai_strerror() catalog for ja_JP.UTF-8 and ja_JP.eucJP. --- lib/libc/nls/ja_JP.UTF-8.msg | 36 ++++++++++++++++++++++++++++++++++++ lib/libc/nls/ja_JP.eucJP.msg | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/nls/ja_JP.UTF-8.msg b/lib/libc/nls/ja_JP.UTF-8.msg index 9ee98d1..b4d2144 100644 --- a/lib/libc/nls/ja_JP.UTF-8.msg +++ b/lib/libc/nls/ja_JP.UTF-8.msg @@ -247,3 +247,39 @@ $ SIGUSR1 30 ユーザ定義シグナル 1 $ SIGUSR2 31 ユーザ定義シグナル 2 +$ +$ gai_strerror() support catalog +$ +$set 3 +$ 1 (obsolete) +1 ホスト名のアドレスファミリーはサポートされません +$ EAI_AGAIN +2 名前解決での一時的な失敗 +$ EAI_BADFLAGS +3 ai_flags の値が無効 +$ EAI_FAIL +4 名前解決での回復不能な失敗 +$ EAI_FAMILY +5 ai_family はサポートされません +$ EAI_MEMORY +6 メモリ割り当て失敗 +$ 7 (obsolete) +7 ホスト名に対応するアドレスはありません +$ EAI_NONAME +8 ホスト名かサービス名が指定されない、または不明 +$ EAI_SERVICE +9 サービス名は ai_socktype に対してサポートされません +$ EAI_SOCKTYPE +10 ai_socktype はサポートされません +$ EAI_SYSTEM +11 システムエラー、errno 参照 +$ EAI_BADHINTS +12 hints の値が無効 +$ EAI_PROTOCOL +13 解決されたプロトコルは不明です +$ EAI_OVERFLOW +14 引数バッファオーバフロー +$ 0 +32766 成功 +$ NL_MSGMAX +32767 不明なエラー diff --git a/lib/libc/nls/ja_JP.eucJP.msg b/lib/libc/nls/ja_JP.eucJP.msg index cba0157..461a39b 100644 --- a/lib/libc/nls/ja_JP.eucJP.msg +++ b/lib/libc/nls/ja_JP.eucJP.msg @@ -247,3 +247,39 @@ $ SIGUSR1 30 桼ʥ 1 $ SIGUSR2 31 桼ʥ 2 +$ +$ gai_strerror() support catalog +$ +$set 3 +$ 1 (obsolete) +1 ۥ̾Υɥ쥹եߥ꡼ϥݡȤޤ +$ EAI_AGAIN +2 ̾ǤΰŪʼ +$ EAI_BADFLAGS +3 ai_flags ̵ͤ +$ EAI_FAIL +4 ̾Ǥβǽʼ +$ EAI_FAMILY +5 ai_family ϥݡȤޤ +$ EAI_MEMORY +6 Ƽ +$ 7 (obsolete) +7 ۥ̾б륢ɥ쥹Ϥޤ +$ EAI_NONAME +8 ۥ̾ӥ̾ꤵʤޤ +$ EAI_SERVICE +9 ӥ̾ ai_socktype ФƥݡȤޤ +$ EAI_SOCKTYPE +10 ai_socktype ϥݡȤޤ +$ EAI_SYSTEM +11 ƥ२顼errno +$ EAI_BADHINTS +12 hints ̵ͤ +$ EAI_PROTOCOL +13 褵줿ץȥǤ +$ EAI_OVERFLOW +14 ХåեХե +$ 0 +32766 +$ NL_MSGMAX +32767 ʥ顼 -- cgit v1.1 From 700ad531607111066c97cf7f1a7962f53f9ef596 Mon Sep 17 00:00:00 2001 From: ume Date: Tue, 10 Nov 2009 03:56:51 +0000 Subject: Add Japanese catalogue entries for newer errnos: EBADMSG, EMULTIHOP, ENOLINK, EPROTO, ENOTCAPABLE. --- lib/libc/nls/ja_JP.UTF-8.msg | 10 ++++++++++ lib/libc/nls/ja_JP.eucJP.msg | 10 ++++++++++ 2 files changed, 20 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/nls/ja_JP.UTF-8.msg b/lib/libc/nls/ja_JP.UTF-8.msg index b4d2144..6be65fb 100644 --- a/lib/libc/nls/ja_JP.UTF-8.msg +++ b/lib/libc/nls/ja_JP.UTF-8.msg @@ -181,6 +181,16 @@ $ ENOATTR 87 そのような属性はありません $ EDOOFUS 88 プログラミングエラーです +$ EBADMSG +89 無効なメッセージです +$ EMULTIHOP +90 マルチホップが試みられました +$ ENOLINK +91 リンクが切断されています +$ EPROTO +92 プロトコルエラーです +$ ENOTCAPABLE +93 ケーパビリティが不足です $ $ strsignal() support catalog $ diff --git a/lib/libc/nls/ja_JP.eucJP.msg b/lib/libc/nls/ja_JP.eucJP.msg index 461a39b..e3fac48 100644 --- a/lib/libc/nls/ja_JP.eucJP.msg +++ b/lib/libc/nls/ja_JP.eucJP.msg @@ -181,6 +181,16 @@ $ ENOATTR 87 Τ褦°Ϥޤ $ EDOOFUS 88 ץߥ󥰥顼Ǥ +$ EBADMSG +89 ̵ʥåǤ +$ EMULTIHOP +90 ޥۥåפߤޤ +$ ENOLINK +91 󥯤ǤƤޤ +$ EPROTO +92 ץȥ륨顼Ǥ +$ ENOTCAPABLE +93 ѥӥƥ­Ǥ $ $ strsignal() support catalog $ -- cgit v1.1 From ec9fee44c1f7884b35b706c71f50b8256a563291 Mon Sep 17 00:00:00 2001 From: roam Date: Wed, 11 Nov 2009 11:31:02 +0000 Subject: Fix the grammar as in the PR, and then some. PR: 140454 Submitted by: Jeremy Huddleston MFC after: 2 weeks --- lib/libc/locale/isblank.3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/locale/isblank.3 b/lib/libc/locale/isblank.3 index 4cc6bbb..6734dcc 100644 --- a/lib/libc/locale/isblank.3 +++ b/lib/libc/locale/isblank.3 @@ -50,9 +50,9 @@ For any locale, this includes the following standard characters: .It "\&``\et''\t`` ''" .El .Pp -In the "C" locale +In the "C" locale, a successful .Fn isblank -successful test is limited to this characters only. +test is limited to these characters only. The value of the argument must be representable as an .Vt "unsigned char" or the value of -- cgit v1.1 From 2a2df770dc273d9bdd8106d636a25d85954fccd0 Mon Sep 17 00:00:00 2001 From: ume Date: Wed, 11 Nov 2009 15:21:06 +0000 Subject: ANSIfy. MFC after: 1 week --- lib/libc/net/ip6opt.c | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/net/ip6opt.c b/lib/libc/net/ip6opt.c index 7b65d06..d999fd4 100644 --- a/lib/libc/net/ip6opt.c +++ b/lib/libc/net/ip6opt.c @@ -55,8 +55,7 @@ static void inet6_insert_padopt(u_char *p, int len); * byte, the length byte, and the option data. */ int -inet6_option_space(nbytes) - int nbytes; +inet6_option_space(int nbytes) { nbytes += 2; /* we need space for nxt-hdr and length fields */ return(CMSG_SPACE((nbytes + 7) & ~7)); @@ -68,10 +67,7 @@ inet6_option_space(nbytes) * success or -1 on an error. */ int -inet6_option_init(bp, cmsgp, type) - void *bp; - struct cmsghdr **cmsgp; - int type; +inet6_option_init(void *bp, struct cmsghdr **cmsgp, int type) { struct cmsghdr *ch = (struct cmsghdr *)bp; @@ -98,11 +94,8 @@ inet6_option_init(bp, cmsgp, type) * earlier. It must have a value between 0 and 7, inclusive. */ int -inet6_option_append(cmsg, typep, multx, plusy) - struct cmsghdr *cmsg; - const u_int8_t *typep; - int multx; - int plusy; +inet6_option_append(struct cmsghdr *cmsg, const u_int8_t *typep, int multx, + int plusy) { int padlen, optlen, off; u_char *bp = (u_char *)cmsg + cmsg->cmsg_len; @@ -171,11 +164,7 @@ inet6_option_append(cmsg, typep, multx, plusy) * */ u_int8_t * -inet6_option_alloc(cmsg, datalen, multx, plusy) - struct cmsghdr *cmsg; - int datalen; - int multx; - int plusy; +inet6_option_alloc(struct cmsghdr *cmsg, int datalen, int multx, int plusy) { int padlen, off; u_int8_t *bp = (u_char *)cmsg + cmsg->cmsg_len; @@ -238,9 +227,7 @@ inet6_option_alloc(cmsg, datalen, multx, plusy) * (RFC 2292, 6.3.5) */ int -inet6_option_next(cmsg, tptrp) - const struct cmsghdr *cmsg; - u_int8_t **tptrp; +inet6_option_next(const struct cmsghdr *cmsg, u_int8_t **tptrp) { struct ip6_ext *ip6e; int hdrlen, optlen; @@ -296,10 +283,7 @@ inet6_option_next(cmsg, tptrp) * it's a typo. The variable should be type of u_int8_t **. */ int -inet6_option_find(cmsg, tptrp, type) - const struct cmsghdr *cmsg; - u_int8_t **tptrp; - int type; +inet6_option_find(const struct cmsghdr *cmsg, u_int8_t **tptrp, int type) { struct ip6_ext *ip6e; int hdrlen, optlen; @@ -352,8 +336,7 @@ inet6_option_find(cmsg, tptrp, type) * calculated length and the limitation of the buffer. */ static int -ip6optlen(opt, lim) - u_int8_t *opt, *lim; +ip6optlen(u_int8_t *opt, u_int8_t *lim) { int optlen; -- cgit v1.1 From 8ecd96b1ed071f237a3fc164cec4960dd679cc98 Mon Sep 17 00:00:00 2001 From: rene Date: Wed, 11 Nov 2009 18:28:12 +0000 Subject: Synchronize with C.msg revision 199083 and improve some existing messages. Reviewed by: remko Approved by: remko --- lib/libc/nls/nl_NL.ISO8859-1.msg | 87 ++++++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 30 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/nls/nl_NL.ISO8859-1.msg b/lib/libc/nls/nl_NL.ISO8859-1.msg index 47103d4..2939116 100644 --- a/lib/libc/nls/nl_NL.ISO8859-1.msg +++ b/lib/libc/nls/nl_NL.ISO8859-1.msg @@ -26,7 +26,7 @@ $ EBADF $ ECHILD 10 Geen kindprocessen $ EDEADLK -11 Een deadlock is vermeden +11 Een deadlock op een bron is vermeden $ ENOMEM 12 Kan geen geheugen meer verkrijgen $ EACCES @@ -40,13 +40,13 @@ $ EBUSY $ EEXIST 17 Bestand bestaat reeds $ EXDEV -18 Verwijzing tussen bestanden op verschillende bestandssystemen +18 Verwijzing tussen verschillende apparaten $ ENODEV 19 Bewerking wordt niet ondersteund door dit apparaat $ ENOTDIR 20 Dit is geen map $ EISDIR -21 Dit is een map +21 Dit is een map $ EINVAL 22 Ongeldig argument $ ENFILE @@ -62,7 +62,7 @@ $ EFBIG $ ENOSPC 28 Geen ruimte meer op dit apparaat $ ESPIPE -29 Onuitvoerbare zoekopdracht +29 Ongeldige zoekopdracht $ EROFS 30 Van dit bestandssysteem kan alleen worden gelezen $ EMLINK @@ -84,7 +84,7 @@ $ ENOTSOCK $ EDESTADDRREQ 39 Een bestemmingsadres is vereist $ EMSGSIZE -40 Te grote bericht +40 Te groot bericht $ EPROTOTYPE 41 Protocol past niet bij dit contactpunt $ ENOPROTOOPT @@ -116,7 +116,7 @@ $ ECONNRESET $ ENOBUFS 55 Geen bufferruimte meer beschikbaar $ EISCONN -56 Dit contactpunt is al verbonden +56 Contactpunt is al verbonden $ ENOTCONN 57 Contactpunt is niet verbonden $ ESHUTDOWN @@ -136,9 +136,9 @@ $ EHOSTDOWN $ EHOSTUNREACH 65 Bestemming niet bereikbaar $ ENOTEMPTY -66 Directory is niet leeg +66 Map is niet leeg $ EPROCLIM -67 Te veel taken +67 Te veel processen $ EUSERS 68 Te veel gebruikers $ EDQUOT @@ -160,7 +160,7 @@ $ EPROCUNAVAIL $ ENOLCK 77 Geen sloten beschikbaar $ ENOSYS -78 Deze systeemfunctie is niet geimplementeerd +78 Systeemfunctie is niet geimplementeerd $ EFTYPE 79 Bestandsformaat niet van toepassing $ EAUTH @@ -173,30 +173,24 @@ $ ENOMSG 83 Geen bericht van het gewenste type $ EOVERFLOW 84 Waarde te groot om te bewaren in gegevenstype -$ EILSEQ -85 Ongeldige bytereeks -$ ENOTSUP -86 Niet ondersteund $ ECANCELED -87 Bewerking geannuleerd -$ EBADMSG -88 Verkeerd of defect bericht -$ ENODATA -89 Geen bericht beschikbaar -$ ENOSR -90 Geen STREAM-voorraad -$ ENOSTR -91 Dit is geen STREAM -$ ETIME -92 STREAM-ioctl verlopen +85 Bewerking geannuleerd +$ EILSEQ +86 Ongeldige bytereeks $ ENOATTR -93 Attribuut niet gevonden +87 Attribuut niet gevonden +$ EDOOFUS +88 Programmeerfout +$ EBADMSG +89 Verkeerd of defect bericht $ EMULTIHOP -94 Multihopverzoek +90 Multihopverzoek $ ENOLINK -95 Verbinding werd verstoord +91 Verbinding werd verstoord $ EPROTO -96 Protocolfout +92 Protocolfout +$ ENOTCAPABLE +93 Onvoldoende mogelijkheden $ $ strsignal() support catalog $ @@ -263,5 +257,38 @@ $ SIGUSR1 30 Gebruikersignaal 1 $ SIGUSR2 31 Gebruikersignaal 2 -$ SIGPWR -32 Stroomuitval/stroominschakeling +$ +$ gai_strerror() support catalog +$set 3 +$ 1 (obsolete) +1 Adresfamilie voor hostnaam niet ondersteund +$ EAI_AGAIN +2 Tijdelijke fout in naamresolutie +$ EAI_BADFLAGS +3 Ongeldige waarde voor ai_flags +$ EAI_FAIL +4 Onherstelbare fout in naamresolutie +$ EAI_FAMILY +5 ai_familie niet ondersteund +$ EAI_MEMORY +6 Geheugenallocatiefout +$ 7 (obsolete) +7 Geen adres met hostnaam geassocieerd +$ EAI_NONAME +8 hostname noch servname gegeven, of onbekend +$ EAI_SERVICE +9 servname niet ondersteund voor ai_socktype +$ EAI_SOCKTYPE +10 ai_socktype niet ondersteund +$ EAI_SYSTEM +11 Systeemfout geretourneerd in errno +$ EAI_BADHINTS +12 Ongeldige waarde voor hints +$ EAI_PROTOCOL +13 Opgelost protocol is onbekend +$ EAI_OVERFLOW +14 Argumentbuffer overstroomd +$ 0 +32766 Succes +$ NL_MSGMAX +32767 Onbekende fout -- cgit v1.1 From 803189ee1c7285f4c03317edb25bdff8329b9757 Mon Sep 17 00:00:00 2001 From: ume Date: Thu, 12 Nov 2009 11:54:12 +0000 Subject: Add missing IEEE1394 support dropped during merge from NetBSD. --- lib/libc/net/getnameinfo.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/net/getnameinfo.c b/lib/libc/net/getnameinfo.c index 0b59586..ffd34a1 100644 --- a/lib/libc/net/getnameinfo.c +++ b/lib/libc/net/getnameinfo.c @@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -385,6 +386,7 @@ getnameinfo_link(const struct sockaddr *sa, socklen_t salen, { const struct sockaddr_dl *sdl = (const struct sockaddr_dl *)(const void *)sa; + const struct fw_hwaddr *iha; int n; if (serv != NULL && servlen > 0) @@ -400,6 +402,15 @@ getnameinfo_link(const struct sockaddr *sa, socklen_t salen, } switch (sdl->sdl_type) { + case IFT_IEEE1394: + if (sdl->sdl_alen < sizeof(iha->sender_unique_ID_hi) + + sizeof(iha->sender_unique_ID_lo)) + return EAI_FAMILY; + iha = (const struct fw_hwaddr *)(const void *)LLADDR(sdl); + return hexname((const u_int8_t *)&iha->sender_unique_ID_hi, + sizeof(iha->sender_unique_ID_hi) + + sizeof(iha->sender_unique_ID_lo), + host, hostlen); /* * The following have zero-length addresses. * IFT_ATM (net/if_atmsubr.c) -- cgit v1.1 From 668062ce478e472d55430d4db23e18ff92d2bd7f Mon Sep 17 00:00:00 2001 From: roam Date: Fri, 13 Nov 2009 09:03:50 +0000 Subject: Fix the grammar in the isgraph(3) description, almost as per the PR. PR: 140455 Submitted by: Jeremy Huddleston MFC after: 2 weeks --- lib/libc/locale/isgraph.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/locale/isgraph.3 b/lib/libc/locale/isgraph.3 index 4ba78e3..5e06e2e 100644 --- a/lib/libc/locale/isgraph.3 +++ b/lib/libc/locale/isgraph.3 @@ -50,7 +50,7 @@ The function tests for any printing character except space .Pq Ql "\ " and other -locale specific space-like characters. +locale-specific space-like characters. The value of the argument must be representable as an .Vt "unsigned char" or the value of -- cgit v1.1 From 6a7fcf918461d74e7024d853a3e74df5894980c0 Mon Sep 17 00:00:00 2001 From: roam Date: Fri, 13 Nov 2009 09:07:33 +0000 Subject: Fix the grammar in the isprint(3) description. PR: 140456 Submitted by: Jeremy Huddleston --- lib/libc/locale/isprint.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/locale/isprint.3 b/lib/libc/locale/isprint.3 index f340850..d8adf1d 100644 --- a/lib/libc/locale/isprint.3 +++ b/lib/libc/locale/isprint.3 @@ -47,7 +47,7 @@ .Sh DESCRIPTION The .Fn isprint -function tests for any printing character including space +function tests for any printing character, including space .Pq Ql "\ " . The value of the argument must be representable as an .Vt "unsigned char" -- cgit v1.1 From a9f932df0f9837cdd04311f9897f1c5a6258f1dc Mon Sep 17 00:00:00 2001 From: brueffer Date: Fri, 13 Nov 2009 13:13:35 +0000 Subject: Improved the manpage description. The committed wording was provided by jhb. PR: 140528 Submitted by: Chris Petrik Discussed with: remko, jhb and the submitter MFC after: 1 week --- lib/libc/sys/vfork.2 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/sys/vfork.2 b/lib/libc/sys/vfork.2 index 928130b..75b2982 100644 --- a/lib/libc/sys/vfork.2 +++ b/lib/libc/sys/vfork.2 @@ -28,12 +28,12 @@ .\" @(#)vfork.2 8.1 (Berkeley) 6/4/93 .\" $FreeBSD$ .\" -.Dd June 4, 1993 +.Dd November 13, 2009 .Dt VFORK 2 .Os .Sh NAME .Nm vfork -.Nd spawn new process in a virtual memory efficient way +.Nd create a new process without copying the address space .Sh LIBRARY .Lb libc .Sh SYNOPSIS -- cgit v1.1 From 2e85514520bfcc1da9b5bf1eb6f848ad9ba44e39 Mon Sep 17 00:00:00 2001 From: brueffer Date: Fri, 13 Nov 2009 13:26:27 +0000 Subject: Remove a note about vfork(4) going to be eliminated, it's here to stay. Submitted by: kib MFC after: 1 week --- lib/libc/sys/vfork.2 | 8 -------- 1 file changed, 8 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/sys/vfork.2 b/lib/libc/sys/vfork.2 index 75b2982..3cd3368 100644 --- a/lib/libc/sys/vfork.2 +++ b/lib/libc/sys/vfork.2 @@ -113,14 +113,6 @@ The system call appeared in .Bx 2.9 . .Sh BUGS -This system call will be eliminated when proper system sharing -mechanisms are implemented. -Users should not depend on the memory -sharing semantics of -.Fn vfork -as it will, in that case, be made synonymous to -.Xr fork 2 . -.Pp To avoid a possible deadlock situation, processes that are children in the middle of a -- cgit v1.1 From 4b1529ed294784d4fdd353a1db7c14d55cc4a985 Mon Sep 17 00:00:00 2001 From: cperciva Date: Sat, 14 Nov 2009 09:31:47 +0000 Subject: Change the utrace log entry for malloc_init from (0, 0, 0) to (-1, 0, 0) in order to distinguish it from free(NULL), which is logged as (0, 0, 0). Reviewed by: jhb --- lib/libc/stdlib/malloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c index bdc26b6..8527496 100644 --- a/lib/libc/stdlib/malloc.c +++ b/lib/libc/stdlib/malloc.c @@ -5116,7 +5116,7 @@ MALLOC_OUT: arena_maxclass = chunksize - (arena_chunk_header_npages << PAGE_SHIFT); - UTRACE(0, 0, 0); + UTRACE((void *)(intptr_t)(-1), 0, 0); #ifdef MALLOC_STATS memset(&stats_chunks, 0, sizeof(chunk_stats_t)); -- cgit v1.1 From 0f3100cf28d51dfe59ee4db0b06ecd48b6aed695 Mon Sep 17 00:00:00 2001 From: brueffer Date: Mon, 16 Nov 2009 09:28:22 +0000 Subject: Fix a memory leak in acl_from_text() in case the conversion succeeded. Submitted by: Jim Wilcoxson MFC after: 1 week --- lib/libc/posix1e/acl_from_text.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/libc') diff --git a/lib/libc/posix1e/acl_from_text.c b/lib/libc/posix1e/acl_from_text.c index 98c5426..c600987 100644 --- a/lib/libc/posix1e/acl_from_text.c +++ b/lib/libc/posix1e/acl_from_text.c @@ -257,6 +257,7 @@ acl_from_text(const char *buf_p) } #endif + free(mybuf_p); return(acl); error_label: -- cgit v1.1 From 9e5ddbc9f2cabb19cf27e27b6cf61349eab2be22 Mon Sep 17 00:00:00 2001 From: brueffer Date: Mon, 16 Nov 2009 14:33:31 +0000 Subject: Fix grammar. PR: 140459 Submitted by: Jeremy Huddleston MFC after: 1 week --- lib/libc/locale/nl_langinfo.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/locale/nl_langinfo.3 b/lib/libc/locale/nl_langinfo.3 index 8de1682..789cac2 100644 --- a/lib/libc/locale/nl_langinfo.3 +++ b/lib/libc/locale/nl_langinfo.3 @@ -53,7 +53,7 @@ with a category corresponding to the category of or to the category .Dv LC_ALL , -may overwrite buffer pointed by the return value. +may overwrite the buffer pointed to by the return value. .Sh RETURN VALUES In a locale where langinfo data is not defined, .Fn nl_langinfo -- cgit v1.1 From 07307010181ba2c6e1d1cfed89b17dc8dc04e649 Mon Sep 17 00:00:00 2001 From: jkim Date: Mon, 16 Nov 2009 19:10:09 +0000 Subject: Sync with C.msg r199083. --- lib/libc/nls/ko_KR.UTF-8.msg | 48 +++++++++++++++++++++++++++++++++++++++++++- lib/libc/nls/ko_KR.eucKR.msg | 48 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 94 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/nls/ko_KR.UTF-8.msg b/lib/libc/nls/ko_KR.UTF-8.msg index 4fc4e78..60e8a12 100644 --- a/lib/libc/nls/ko_KR.UTF-8.msg +++ b/lib/libc/nls/ko_KR.UTF-8.msg @@ -181,6 +181,16 @@ $ ENOATTR 87 속성을 찾을 수 없습니다 $ EDOOFUS 88 프로그램상 오류입니다 +$ EBADMSG +89 잘못된 메시지입니다 +$ EMULTIHOP +90 멀티홉이 시도되었습니다 +$ ENOLINK +91 연결이 끊겼습니다 +$ EPROTO +92 프로토콜이 잘못되었습니다 +$ ENOTCAPABLE +93 접근 능력이 충분치 않습니다 $ $ strsignal() support catalog $ @@ -230,7 +240,7 @@ $ SIGTTIN $ SIGTTOU 22 정지 (터미널 출력) $ SIGIO -23 I/O possible +23 I/O 가능 $ SIGXCPU 24 CPU 사용 시간 초과 $ SIGXFSZ @@ -247,3 +257,39 @@ $ SIGUSR1 30 사용자 정의 시그널 1 $ SIGUSR2 31 사용자 정의 시그널 2 +$ +$ gai_strerror() support catalog +$ +$set 3 +$ 1 (obsolete) +1 호스트 이름이 지원하지 않는 주소군입니다 +$ EAI_AGAIN +2 주소 변환에 일시적으로 실패했습니다 +$ EAI_BADFLAGS +3 잘못된 ai_flags입니다 +$ EAI_FAIL +4 주소 변환에 완전히 실패했습니다 +$ EAI_FAMILY +5 지원되지 않는 ai_family입니다 +$ EAI_MEMORY +6 메모리 할당에 실패했습니다 +$ 7 (obsolete) +7 호스트 이름과 일치하는 주소가 없습니다 +$ EAI_NONAME +8 호스트 이름 또는 서비스 이름이 지정되지 않았거나 알 수 없습니다 +$ EAI_SERVICE +9 서비스 이름은 ai_socktype에서 지원되지 않습니다 +$ EAI_SOCKTYPE +10 지원되지 않는 ai_socktype입니다 +$ EAI_SYSTEM +11 시스템 오류가 errno에 반환되었습니다 +$ EAI_BADHINTS +12 잘못된 hints입니다 +$ EAI_PROTOCOL +13 알 수 없는 프로토콜이 변환되었습니다 +$ EAI_OVERFLOW +14 인자 버퍼 공간이 모자랍니다 +$ 0 +32766 성공 +$ NL_MSGMAX +32767 알 수 없는 오류 diff --git a/lib/libc/nls/ko_KR.eucKR.msg b/lib/libc/nls/ko_KR.eucKR.msg index c2ca1a0..bb1fa30 100644 --- a/lib/libc/nls/ko_KR.eucKR.msg +++ b/lib/libc/nls/ko_KR.eucKR.msg @@ -181,6 +181,16 @@ $ ENOATTR 87 Ӽ ã ϴ $ EDOOFUS 88 α׷ Դϴ +$ EBADMSG +89 ߸ ޽Դϴ +$ EMULTIHOP +90 Ƽȩ õǾϴ +$ ENOLINK +91 ϴ +$ EPROTO +92 ߸Ǿϴ +$ ENOTCAPABLE +93 ɷ ġ ʽϴ $ $ strsignal() support catalog $ @@ -230,7 +240,7 @@ $ SIGTTIN $ SIGTTOU 22 (͹̳ ) $ SIGIO -23 I/O possible +23 I/O $ SIGXCPU 24 CPU ð ʰ $ SIGXFSZ @@ -247,3 +257,39 @@ $ SIGUSR1 30 ñ׳ 1 $ SIGUSR2 31 ñ׳ 2 +$ +$ gai_strerror() support catalog +$ +$set 3 +$ 1 (obsolete) +1 ȣƮ ̸ ʴ ּұԴϴ +$ EAI_AGAIN +2 ּ ȯ Ͻ ߽ϴ +$ EAI_BADFLAGS +3 ߸ ai_flagsԴϴ +$ EAI_FAIL +4 ּ ȯ ߽ϴ +$ EAI_FAMILY +5 ʴ ai_familyԴϴ +$ EAI_MEMORY +6 ޸ Ҵ翡 ߽ϴ +$ 7 (obsolete) +7 ȣƮ ̸ ġϴ ּҰ ϴ +$ EAI_NONAME +8 ȣƮ ̸ Ǵ ̸ ʾҰų ϴ +$ EAI_SERVICE +9 ̸ ai_socktype ʽϴ +$ EAI_SOCKTYPE +10 ʴ ai_socktypeԴϴ +$ EAI_SYSTEM +11 ý errno ȯǾϴ +$ EAI_BADHINTS +12 ߸ hintsԴϴ +$ EAI_PROTOCOL +13 ȯǾϴ +$ EAI_OVERFLOW +14 ڶϴ +$ 0 +32766 +$ NL_MSGMAX +32767 -- cgit v1.1 From 7a582e36614baf11e09a8f5fc8444c3297de67e6 Mon Sep 17 00:00:00 2001 From: obrien Date: Tue, 17 Nov 2009 16:29:39 +0000 Subject: Catch up with r130332 which changed the default timezone from GMT to UTC. Otherwise the tzload() (when called by gmtload()) fails to locate the UTC file and loads the posixrules. --- lib/libc/gen/tzset.3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/tzset.3 b/lib/libc/gen/tzset.3 index 34ca238..8d37fca 100644 --- a/lib/libc/gen/tzset.3 +++ b/lib/libc/gen/tzset.3 @@ -310,14 +310,14 @@ time zone directory rules for .Tn POSIX Ns -style .Tn TZ Ns 's -.It Pa /usr/share/zoneinfo/GMT +.It Pa /usr/share/zoneinfo/Etc/GMT for .Tn UTC leap seconds .El .Pp If the file -.Pa /usr/share/zoneinfo/GMT +.Pa /usr/share/zoneinfo/UTC does not exist, .Tn UTC leap seconds are loaded from -- cgit v1.1 From 3bc020a6915bd5655c89a2da58b539603260fdaf Mon Sep 17 00:00:00 2001 From: gabor Date: Tue, 17 Nov 2009 18:57:44 +0000 Subject: - Update Hungarian libc catalog --- lib/libc/nls/hu_HU.ISO8859-2.msg | 46 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/nls/hu_HU.ISO8859-2.msg b/lib/libc/nls/hu_HU.ISO8859-2.msg index 90b597b..330d486 100644 --- a/lib/libc/nls/hu_HU.ISO8859-2.msg +++ b/lib/libc/nls/hu_HU.ISO8859-2.msg @@ -181,6 +181,16 @@ $ ENOATTR 87 Attribtum nem tallhat $ EDOOFUS 88 Programozsi hiba +$ EBADMSG +89 Helytelen zenet +$ EMULTIHOP +90 Multihop ksrlet +$ ENOLINK +91 A kapcsolat szigortva lett +$ EPROTO +92 Protokol hiba +$ ENOTCAPABLE +93 Elgtelen kpessgek $ $ strsignal() support catalog $ @@ -247,3 +257,39 @@ $ SIGUSR1 30 Felhasznli szignl 1 $ SIGUSR2 31 Felhasznli szignl 2 +$ +$ gai_strerror() support catalog +$ +$set 3 +$ 1 (elavult) +1 A hosztnvhez tartoz cmcsald nem tmogatott +$ EAI_AGAIN +2 Ideiglenes hiba a nvfeloldskor +$ EAI_BADFLAGS +3 rvnytelen ai_flags rtk +$ EAI_FAIL +4 Nem helyrellthat hiba a nvfeloldsban +$ EAI_FAMILY +5 ai_family nem tmogatott +$ EAI_MEMORY +6 Memriafoglalsi hiba +$ 7 (elavult) +7 Nem tartozik cm hosztnvhez +$ EAI_NONAME +8 Se hosztnv, se szolgltatsnv nem ll rendelkezsre +$ EAI_SERVICE +9 Nem tmogatott ai_socktype szolgltatsnv +$ EAI_SOCKTYPE +10 ai_socktype nem tmogatott +$ EAI_SYSTEM +11 Rendszerhiba jtt vissza az errno vltozban +$ EAI_BADHINTS +12 rvnytelen hint rtk +$ EAI_PROTOCOL +13 A feloldott protokol ismeretlen +$ EAI_OVERFLOW +14 Az argumentumok puffere tlcsordult +$ 0 +32766 Siker +$ NL_MSGMAX +32767 Ismeretlen hiba -- cgit v1.1 From b850b4760dddafa38d7850f86e99ce47326a2676 Mon Sep 17 00:00:00 2001 From: jhb Date: Fri, 20 Nov 2009 19:19:51 +0000 Subject: Add an internal _once() method. This works identical to pthread_once(3) with the additional property that it is safe for routines in libc to use in both single-threaded and multi-threaded processes. Multi-threaded processes use the pthread_once() implementation from the threading library while single-threaded processes use a simplified "stub" version internal to libc. The libc stub-version of pthread_once() now also uses the simplified "stub" version as well instead of being a nop. Reviewed by: deischen, Matthew Fleming @ Isilon Suggested by: alc MFC after: 1 week --- lib/libc/gen/Makefile.inc | 3 +- lib/libc/gen/_once_stub.c | 67 +++++++++++++++++++++++++++++++++++++++++ lib/libc/gen/_pthread_stubs.c | 2 +- lib/libc/include/libc_private.h | 8 +++++ 4 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 lib/libc/gen/_once_stub.c (limited to 'lib/libc') diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index 0bdee9d..d6b403e 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -5,7 +5,8 @@ .PATH: ${.CURDIR}/${MACHINE_ARCH}/gen ${.CURDIR}/gen SRCS+= __getosreldate.c __xuname.c \ - _pthread_stubs.c _rand48.c _spinlock_stub.c _thread_init.c \ + _once_stub.c _pthread_stubs.c _rand48.c _spinlock_stub.c \ + _thread_init.c \ alarm.c arc4random.c assert.c basename.c check_utility_compat.c \ clock.c closedir.c confstr.c \ crypt.c ctermid.c daemon.c devname.c dirname.c disklabel.c \ diff --git a/lib/libc/gen/_once_stub.c b/lib/libc/gen/_once_stub.c new file mode 100644 index 0000000..0d20c01 --- /dev/null +++ b/lib/libc/gen/_once_stub.c @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 2009 Advanced Computing Technologies LLC + * Written by: John H. Baldwin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include +#include "un-namespace.h" +#include "libc_private.h" + +/* + * This implements pthread_once() for the single-threaded case. It is + * non-static so that it can be used by _pthread_stubs.c. + */ +int +_libc_once(pthread_once_t *once_control, void (*init_routine)(void)) +{ + + if (once_control->state == PTHREAD_DONE_INIT) + return (0); + init_routine(); + once_control->state = PTHREAD_DONE_INIT; + return (0); +} + +/* + * This is the internal interface provided to libc. It will use + * pthread_once() from the threading library in a multi-threaded + * process and _libc_once() for a single-threaded library. Because + * _libc_once() uses the same ABI for the values in the pthread_once_t + * structure as the threading library, it is safe for a process to + * switch from _libc_once() to pthread_once() when threading is + * enabled. + */ +int +_once(pthread_once_t *once_control, void (*init_routine)(void)) +{ + + if (__isthreaded) + return (_pthread_once(once_control, init_routine)); + return (_libc_once(once_control, init_routine)); +} diff --git a/lib/libc/gen/_pthread_stubs.c b/lib/libc/gen/_pthread_stubs.c index 147235e..3b80e1d 100644 --- a/lib/libc/gen/_pthread_stubs.c +++ b/lib/libc/gen/_pthread_stubs.c @@ -105,7 +105,7 @@ pthread_func_entry_t __thr_jtable[PJT_MAX] = { {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEX_LOCK */ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEX_TRYLOCK */ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEX_UNLOCK */ - {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ONCE */ + {PJT_DUAL_ENTRY(_libc_once)}, /* PJT_ONCE */ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_RWLOCK_DESTROY */ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_RWLOCK_INIT */ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_RWLOCK_RDLOCK */ diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h index 50903f3..bcf2b1c 100644 --- a/lib/libc/include/libc_private.h +++ b/lib/libc/include/libc_private.h @@ -34,6 +34,7 @@ #ifndef _LIBC_PRIVATE_H_ #define _LIBC_PRIVATE_H_ +#include /* * This global flag is non-zero when a process has created one @@ -147,6 +148,13 @@ int _yp_check(char **); void _init_tls(void); /* + * Provides pthread_once()-like functionality for both single-threaded + * and multi-threaded applications. + */ +int _once(pthread_once_t *, void (*)(void)); +int _libc_once(pthread_once_t *, void (*)(void)); + +/* * Set the TLS thread pointer */ void _set_tp(void *tp); -- cgit v1.1 From 7ccf9228d7906bfeaa829ac304867443a65e7056 Mon Sep 17 00:00:00 2001 From: jhb Date: Fri, 20 Nov 2009 19:21:33 +0000 Subject: Replace gmt_is_set and the gmt_mutex lock with a pthread_once_t variable and an init routine run on the first invocation via _once(). MFC after: 1 week --- lib/libc/stdtime/localtime.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdtime/localtime.c b/lib/libc/stdtime/localtime.c index 9fc5f3e..d391e3e 100644 --- a/lib/libc/stdtime/localtime.c +++ b/lib/libc/stdtime/localtime.c @@ -235,9 +235,8 @@ static struct state gmtmem; static char lcl_TZname[TZ_STRLEN_MAX + 1]; static int lcl_is_set; -static int gmt_is_set; +static pthread_once_t gmt_once = PTHREAD_ONCE_INIT; static pthread_rwlock_t lcl_rwlock = PTHREAD_RWLOCK_INITIALIZER; -static pthread_mutex_t gmt_mutex = PTHREAD_MUTEX_INITIALIZER; char * tzname[2] = { wildabbr, @@ -1464,6 +1463,17 @@ struct tm * tmp; return tmp; } +static void +gmt_init(void) +{ + +#ifdef ALL_STATE + gmtptr = (struct state *) malloc(sizeof *gmtptr); + if (gmtptr != NULL) +#endif /* defined ALL_STATE */ + gmtload(gmtptr); +} + /* ** gmtsub is to gmtime as localsub is to localtime. */ @@ -1476,16 +1486,7 @@ struct tm * const tmp; { register struct tm * result; - _MUTEX_LOCK(&gmt_mutex); - if (!gmt_is_set) { -#ifdef ALL_STATE - gmtptr = (struct state *) malloc(sizeof *gmtptr); - if (gmtptr != NULL) -#endif /* defined ALL_STATE */ - gmtload(gmtptr); - gmt_is_set = TRUE; - } - _MUTEX_UNLOCK(&gmt_mutex); + _once(&gmt_once, gmt_init); result = timesub(timep, offset, gmtptr, tmp); #ifdef TM_ZONE /* -- cgit v1.1 From e66ae1c3f9bd142ce98d9a41f908d7e62fca76af Mon Sep 17 00:00:00 2001 From: jhb Date: Fri, 20 Nov 2009 20:43:34 +0000 Subject: Revert the previous change to pthread_once() stub in libc. It is actually a feature that libstdc++ depends on to simulate the behavior of libc's internal '__isthreaded' variable. One benefit of this is that _libc_once() is now private to _once_stub.c. Requested by: kan --- lib/libc/gen/_once_stub.c | 7 ++----- lib/libc/gen/_pthread_stubs.c | 2 +- lib/libc/include/libc_private.h | 1 - 3 files changed, 3 insertions(+), 7 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/_once_stub.c b/lib/libc/gen/_once_stub.c index 0d20c01..d2acc29 100644 --- a/lib/libc/gen/_once_stub.c +++ b/lib/libc/gen/_once_stub.c @@ -33,11 +33,8 @@ __FBSDID("$FreeBSD$"); #include "un-namespace.h" #include "libc_private.h" -/* - * This implements pthread_once() for the single-threaded case. It is - * non-static so that it can be used by _pthread_stubs.c. - */ -int +/* This implements pthread_once() for the single-threaded case. */ +static int _libc_once(pthread_once_t *once_control, void (*init_routine)(void)) { diff --git a/lib/libc/gen/_pthread_stubs.c b/lib/libc/gen/_pthread_stubs.c index 3b80e1d..147235e 100644 --- a/lib/libc/gen/_pthread_stubs.c +++ b/lib/libc/gen/_pthread_stubs.c @@ -105,7 +105,7 @@ pthread_func_entry_t __thr_jtable[PJT_MAX] = { {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEX_LOCK */ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEX_TRYLOCK */ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEX_UNLOCK */ - {PJT_DUAL_ENTRY(_libc_once)}, /* PJT_ONCE */ + {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ONCE */ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_RWLOCK_DESTROY */ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_RWLOCK_INIT */ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_RWLOCK_RDLOCK */ diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h index bcf2b1c..052eb13 100644 --- a/lib/libc/include/libc_private.h +++ b/lib/libc/include/libc_private.h @@ -152,7 +152,6 @@ void _init_tls(void); * and multi-threaded applications. */ int _once(pthread_once_t *, void (*)(void)); -int _libc_once(pthread_once_t *, void (*)(void)); /* * Set the TLS thread pointer -- cgit v1.1 From f44a6f4d8d88c80474b25b8be3da936d6c652bb1 Mon Sep 17 00:00:00 2001 From: wollman Date: Wed, 25 Nov 2009 04:21:42 +0000 Subject: Eliminate dead store. Found by: Clang static analyzer MFC after: 7 days --- lib/libc/stdio/fvwrite.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/stdio/fvwrite.c b/lib/libc/stdio/fvwrite.c index fd69eb9..7206676 100644 --- a/lib/libc/stdio/fvwrite.c +++ b/lib/libc/stdio/fvwrite.c @@ -60,7 +60,7 @@ __sfvwrite(fp, uio) char *nl; int nlknown, nldist; - if ((len = uio->uio_resid) == 0) + if (uio->uio_resid == 0) return (0); /* make sure we can write */ if (prepwrite(fp) != 0) -- cgit v1.1 From b15e7bd9790eb41e97bbef83cfa1f1d778e2e7e2 Mon Sep 17 00:00:00 2001 From: wollman Date: Wed, 25 Nov 2009 04:27:55 +0000 Subject: In __mbsconv(), if prec was zero, nconv could have been used uninitialized. Initialize it to a safe value so that there's no chance of returning an error if stack garbage happens to be equal to (size_t)-1 or (size_t)-2. Found by: Clang static analyzer MFC after: 7 days --- lib/libc/stdio/vfwprintf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/stdio/vfwprintf.c b/lib/libc/stdio/vfwprintf.c index f3768de..d34f559 100644 --- a/lib/libc/stdio/vfwprintf.c +++ b/lib/libc/stdio/vfwprintf.c @@ -293,7 +293,7 @@ __mbsconv(char *mbsarg, int prec) * number of characters to print. */ p = mbsarg; - insize = nchars = 0; + insize = nchars = nconv = 0; mbs = initial_mbs; while (nchars != (size_t)prec) { nconv = mbrlen(p, MB_CUR_MAX, &mbs); -- cgit v1.1 From 0bb16760a11c0384ebde0564be95b7c5711ce69e Mon Sep 17 00:00:00 2001 From: wollman Date: Wed, 25 Nov 2009 04:35:54 +0000 Subject: Make all three if conditions look similar by always initializing nsec and moving the default initialization of prec into the else clause. The clang static analyzer erroneously thought that nsec can be used uninitialized here; it was not actually possible, but better to make the code clearer. (Clang can't know that sprintf() won't modify *pi behind the scenes.) --- lib/libc/stdio/xprintf_time.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/stdio/xprintf_time.c b/lib/libc/stdio/xprintf_time.c index 81697f1..9d732fe 100644 --- a/lib/libc/stdio/xprintf_time.c +++ b/lib/libc/stdio/xprintf_time.c @@ -64,7 +64,6 @@ __printf_render_time(struct __printf_io *io, const struct printf_info *pi, const intmax_t t, tx; int i, prec, nsec; - prec = 0; if (pi->is_long) { tv = *((struct timeval **)arg[0]); t = tv->tv_sec; @@ -78,6 +77,8 @@ __printf_render_time(struct __printf_io *io, const struct printf_info *pi, const } else { tp = *((time_t **)arg[0]); t = *tp; + nsec = 0; + prec = 0; } p = buf; -- cgit v1.1 From a98dd21d5f02e42d66bdd19531580000647322e8 Mon Sep 17 00:00:00 2001 From: wollman Date: Wed, 25 Nov 2009 04:45:45 +0000 Subject: Eliminate more dead stores. Found by: Clang static analyzer MFC after: 7 days --- lib/libc/gen/getcap.c | 5 ++--- lib/libc/gen/getusershell.c | 2 +- lib/libc/gen/wordexp.c | 2 +- lib/libc/rpc/getnetconfig.c | 4 ++-- lib/libc/rpc/key_call.c | 2 +- lib/libc/stdio/fgetws.c | 2 +- lib/libc/yp/yplib.c | 2 +- 7 files changed, 9 insertions(+), 10 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/getcap.c b/lib/libc/gen/getcap.c index 32d66d48..2700d3d 100644 --- a/lib/libc/gen/getcap.c +++ b/lib/libc/gen/getcap.c @@ -647,7 +647,7 @@ int cgetnext(char **bp, char **db_array) { size_t len; - int done, hadreaderr, i, savederrno, status; + int done, hadreaderr, savederrno, status; char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE]; u_int dummy; @@ -658,7 +658,7 @@ cgetnext(char **bp, char **db_array) (void)cgetclose(); return (-1); } - for(;;) { + for (;;) { if (toprec && !gottoprec) { gottoprec = 1; line = toprec; @@ -709,7 +709,6 @@ cgetnext(char **bp, char **db_array) /* * Line points to a name line. */ - i = 0; done = 0; np = nbuf; for (;;) { diff --git a/lib/libc/gen/getusershell.c b/lib/libc/gen/getusershell.c index b0da2a1..d09b50c 100644 --- a/lib/libc/gen/getusershell.c +++ b/lib/libc/gen/getusershell.c @@ -124,7 +124,7 @@ _local_initshells(rv, cb_data, ap) if ((fp = fopen(_PATH_SHELLS, "r")) == NULL) return NS_UNAVAIL; - sp = cp = line; + cp = line; while (fgets(cp, MAXPATHLEN + 1, fp) != NULL) { while (*cp != '#' && *cp != '/' && *cp != '\0') cp++; diff --git a/lib/libc/gen/wordexp.c b/lib/libc/gen/wordexp.c index 06abdc7..bcab1f5 100644 --- a/lib/libc/gen/wordexp.c +++ b/lib/libc/gen/wordexp.c @@ -320,7 +320,7 @@ we_check(const char *words, int flags) if (c == '\0' || level != 0) return (WRDE_SYNTAX); } else - c = *--words; + --words; break; default: break; diff --git a/lib/libc/rpc/getnetconfig.c b/lib/libc/rpc/getnetconfig.c index 9baa224..e5db51a 100644 --- a/lib/libc/rpc/getnetconfig.c +++ b/lib/libc/rpc/getnetconfig.c @@ -412,13 +412,13 @@ void *handlep; * Noone needs these entries anymore, then frees them. * Make sure all info in netconfig_info structure has been reinitialized. */ - q = p = ni.head; + q = ni.head; ni.eof = ni.ref = 0; ni.head = NULL; ni.tail = NULL; mutex_unlock(&ni_lock); - while (q) { + while (q != NULL) { p = q->next; if (q->ncp->nc_lookups != NULL) free(q->ncp->nc_lookups); free(q->ncp); diff --git a/lib/libc/rpc/key_call.c b/lib/libc/rpc/key_call.c index 615f24d..6cc1139 100644 --- a/lib/libc/rpc/key_call.c +++ b/lib/libc/rpc/key_call.c @@ -302,7 +302,7 @@ int vers; void *localhandle; struct netconfig *nconf; struct netconfig *tpconf; - struct key_call_private *kcp = key_call_private_main; + struct key_call_private *kcp; struct timeval wait_time; struct utsname u; int main_thread; diff --git a/lib/libc/stdio/fgetws.c b/lib/libc/stdio/fgetws.c index bbc0299..550843d 100644 --- a/lib/libc/stdio/fgetws.c +++ b/lib/libc/stdio/fgetws.c @@ -89,7 +89,7 @@ fgetws(wchar_t * __restrict ws, int n, FILE * __restrict fp) if (!__mbsinit(&fp->_mbstate)) /* Incomplete character */ goto error; - *wsp++ = L'\0'; + *wsp = L'\0'; FUNLOCKFILE(fp); return (ws); diff --git a/lib/libc/yp/yplib.c b/lib/libc/yp/yplib.c index eb5c34c..87d16dd 100644 --- a/lib/libc/yp/yplib.c +++ b/lib/libc/yp/yplib.c @@ -241,7 +241,7 @@ static bool_t ypmatch_cache_lookup(struct dom_binding *ypdb, char *map, keydat *key, valdat *val) { - struct ypmatch_ent *c = ypdb->cache; + struct ypmatch_ent *c; ypmatch_cache_expire(ypdb); -- cgit v1.1 From d0aa37ef30706d9707ef8ebd9e7f45542fb22540 Mon Sep 17 00:00:00 2001 From: wollman Date: Wed, 25 Nov 2009 04:49:41 +0000 Subject: In svc_raw_reply(), don't leave stat uninitialized if the MSG_ACCEPTED && SUCCESS case succeeds. The stack garbage might be zero. Found by: Clang static analyzer MFC after: 7 days --- lib/libc/rpc/svc_raw.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/rpc/svc_raw.c b/lib/libc/rpc/svc_raw.c index 7492046..67bcba1 100644 --- a/lib/libc/rpc/svc_raw.c +++ b/lib/libc/rpc/svc_raw.c @@ -176,9 +176,8 @@ svc_raw_reply(xprt, msg) msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; msg->acpted_rply.ar_results.where = NULL; - if (!xdr_replymsg(xdrs, msg) || - !SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where)) - stat = FALSE; + stat = xdr_replymsg(xdrs, msg) && + SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where); } else { stat = xdr_replymsg(xdrs, msg); } -- cgit v1.1 From 9d981856ee4aad156fa0d3449733e6a974130e44 Mon Sep 17 00:00:00 2001 From: wollman Date: Wed, 25 Nov 2009 04:52:12 +0000 Subject: In clnt_raw_create(), avoid minor race condition initializing the file-scope variable clntraw_private. Found by: Clang static analyzer MFC after: 7 days --- lib/libc/rpc/clnt_raw.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/rpc/clnt_raw.c b/lib/libc/rpc/clnt_raw.c index 9d34a3d..cd3a384 100644 --- a/lib/libc/rpc/clnt_raw.c +++ b/lib/libc/rpc/clnt_raw.c @@ -92,13 +92,13 @@ clnt_raw_create(prog, vers) rpcprog_t prog; rpcvers_t vers; { - struct clntraw_private *clp = clntraw_private; + struct clntraw_private *clp; struct rpc_msg call_msg; - XDR *xdrs = &clp->xdr_stream; - CLIENT *client = &clp->client_object; + XDR *xdrs; + CLIENT *client; mutex_lock(&clntraw_lock); - if (clp == NULL) { + if ((clp = clntraw_private) == NULL) { clp = (struct clntraw_private *)calloc(1, sizeof (*clp)); if (clp == NULL) { mutex_unlock(&clntraw_lock); @@ -110,6 +110,9 @@ clnt_raw_create(prog, vers) clp->_raw_buf = __rpc_rawcombuf; clntraw_private = clp; } + xdrs = &clp->xdr_stream; + client = &clp->client_object; + /* * pre-serialize the static part of the call msg and stash it away */ -- cgit v1.1 From b9acef29825e46c891a2f4baccde0ff64409e5e9 Mon Sep 17 00:00:00 2001 From: wollman Date: Wed, 25 Nov 2009 04:53:38 +0000 Subject: Style: use structure assignment rather than memcpy() to copy a structure. --- lib/libc/rpc/getrpcent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/rpc/getrpcent.c b/lib/libc/rpc/getrpcent.c index abee480..1f198fa 100644 --- a/lib/libc/rpc/getrpcent.c +++ b/lib/libc/rpc/getrpcent.c @@ -698,7 +698,7 @@ rpc_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap, return (NS_RETURN); } - memcpy(&new_rpc, rpc, sizeof(struct rpcent)); + new_rpc = *rpc; *buffer_size = desired_size; memset(buffer, 0, desired_size); -- cgit v1.1 From 878f33c39357795d6a94d97a21c503a52b96cb9e Mon Sep 17 00:00:00 2001 From: kib Date: Thu, 26 Nov 2009 13:49:37 +0000 Subject: Implement sighold, sigignore, sigpause, sigrelse, sigset functions from SUSv4 XSI. Note that the functions are obsoleted, and only provided to ease porting from System V-like systems. Since sigpause already exists in compat with different interface, XSI sigpause is named xsi_sigpause. Reviewed by: davidxu MFC after: 3 weeks --- lib/libc/compat-43/Makefile.inc | 5 ++ lib/libc/compat-43/Symbol.map | 8 ++ lib/libc/compat-43/sigcompat.c | 85 ++++++++++++++++++++- lib/libc/compat-43/sigpause.2 | 160 ++++++++++++++++++++++++++++++++++++++-- 4 files changed, 250 insertions(+), 8 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/compat-43/Makefile.inc b/lib/libc/compat-43/Makefile.inc index 836f0a6..8505ff2 100644 --- a/lib/libc/compat-43/Makefile.inc +++ b/lib/libc/compat-43/Makefile.inc @@ -13,6 +13,11 @@ MAN+= creat.2 killpg.2 sigpause.2 sigsetmask.2 sigvec.2 MAN+= gethostid.3 setruid.3 MLINKS+=gethostid.3 sethostid.3 +MLINKS+=sigpause.2 sighold.2 +MLINKS+=sigpause.2 sigignore.2 +MLINKS+=sigpause.2 sigrelse.2 +MLINKS+=sigpause.2 sigset.2 +MLINKS+=sigpause.2 xsi_sigpause.2 MLINKS+=setruid.3 setrgid.3 MLINKS+=sigsetmask.2 sigblock.2 diff --git a/lib/libc/compat-43/Symbol.map b/lib/libc/compat-43/Symbol.map index e859a31..bd49f99 100644 --- a/lib/libc/compat-43/Symbol.map +++ b/lib/libc/compat-43/Symbol.map @@ -17,6 +17,14 @@ FBSD_1.0 { sigvec; }; +FBSD_1.2 { + sighold; + sigignore; + sigrelse; + sigset; + xsi_sigpause; +}; + FBSDprivate_1.0 { __creat; _creat; diff --git a/lib/libc/compat-43/sigcompat.c b/lib/libc/compat-43/sigcompat.c index 6280183..c3ba30a 100644 --- a/lib/libc/compat-43/sigcompat.c +++ b/lib/libc/compat-43/sigcompat.c @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include +#include #include "un-namespace.h" #include "libc_private.h" @@ -97,8 +98,7 @@ sigblock(mask) } int -sigpause(mask) - int mask; +sigpause(int mask) { sigset_t set; @@ -106,3 +106,84 @@ sigpause(mask) set.__bits[0] = mask; return (_sigsuspend(&set)); } + +int +xsi_sigpause(int sig) +{ + sigset_t set; + + sigemptyset(&set); + sigaddset(&set, sig); + return (_sigsuspend(&set)); +} + +int +sighold(int sig) +{ + sigset_t set; + + sigemptyset(&set); + sigaddset(&set, sig); + return (_sigprocmask(SIG_BLOCK, &set, NULL)); +} + +int +sigignore(int sig) +{ + struct sigaction sa; + + bzero(&sa, sizeof(sa)); + sa.sa_handler = SIG_IGN; + return (_sigaction(sig, &sa, NULL)); +} + +int +sigrelse(int sig) +{ + sigset_t set; + + sigemptyset(&set); + sigaddset(&set, sig); + return (_sigprocmask(SIG_UNBLOCK, &set, NULL)); +} + +void +(*sigset(int sig, void (*disp)(int)))(int) +{ + sigset_t set, pset; + struct sigaction sa, psa; + int error; + + sigemptyset(&set); + sigaddset(&set, sig); + error = _sigprocmask(SIG_BLOCK, NULL, &pset); + if (error == -1) + return (SIG_ERR); + if ((__sighandler_t *)disp == SIG_HOLD) { + error = _sigprocmask(SIG_BLOCK, &set, &pset); + if (error == -1) + return (SIG_ERR); + if (sigismember(&pset, sig)) + return (SIG_HOLD); + else { + error = _sigaction(sig, NULL, &psa); + if (error == -1) + return (SIG_ERR); + return (psa.sa_handler); + } + } else { + error = _sigprocmask(SIG_UNBLOCK, &set, &pset); + if (error == -1) + return (SIG_ERR); + } + + bzero(&sa, sizeof(sa)); + sa.sa_handler = disp; + error = _sigaction(sig, &sa, &psa); + if (error == -1) + return (SIG_ERR); + if (sigismember(&pset, sig)) + return (SIG_HOLD); + else + return (psa.sa_handler); +} diff --git a/lib/libc/compat-43/sigpause.2 b/lib/libc/compat-43/sigpause.2 index 39edb0b..bf3cf0b 100644 --- a/lib/libc/compat-43/sigpause.2 +++ b/lib/libc/compat-43/sigpause.2 @@ -28,21 +28,118 @@ .\" @(#)sigpause.2 8.1 (Berkeley) 6/2/93 .\" $FreeBSD$ .\" +.\" Part of the content of the man page was derived from +.\" The Open Group Base Specifications Issue 7 +.\" IEEE Std 1003.1-2008 +.\" .Dd June 2, 1993 .Dt SIGPAUSE 2 .Os .Sh NAME -.Nm sigpause -.Nd atomically release blocked signals and wait for interrupt +.Nm sighold , +.Nm sigignore , +.Nm sigpause , +.Nm sigrelse , +.Nm sigset +.Nd legacy interface for signal management .Sh LIBRARY .Lb libc .Sh SYNOPSIS .In signal.h .Ft int +.Fn sighold "int sig" +.Ft int +.Fn sigignore "int sig" +.Ft int +.Fn xsi_sigpause "int sigmask" +.Ft int +.Fn sigrelse "int sig" +.Ft void (*)(int) +.Fn sigset "int" "void (*disp)(int)" +.Ft int .Fn sigpause "int sigmask" .Sh DESCRIPTION .Sy This interface is made obsolete by -.Xr sigsuspend 2 . +.Xr sigsuspend 2 +.Sy and +.Xr sigaction 2 +.Pp +The +.Fn sigset +function modifies signal dispositions. +The +.Fa sig +argument specifies the signal, which may be any signal except +.Dv SIGKILL +and +.Dv SIGSTOP . +The +.Fa disp +argument specifies the signal's disposition, +which may be +.Dv SIG_DFL , +.Dv SIG_IGN , +or the address of a signal handler. +If +.Fn sigset +is used, and +.Fa disp +is the address of a signal handler, the +system adds +.Fa sig +to the signal mask of the calling process before executing the signal +handler; when the signal handler returns, the system restores the +signal mask of the calling process to its state prior to the delivery +of the signal. +In addition, if +.Fn sigset +is used, and +.Fa disp +is equal to +.Dv SIG_HOLD , +.Fa sig +is added to the signal +mask of the calling process and +.Fa sig 's +disposition remains unchanged. +If +.Fn sigset +is used, and +.Fa disp +is not equal to +.Dv SIG_HOLD , +.Fa sig +is removed from the signal mask of the calling process. +.Pp +The +.Fn sighold +function adds +.Fa sig +to the signal mask of the calling process. +.Pp +The +.Fn sigrelse +function removes +.Fa sig +from the signal mask of the calling process. +.Pp +The +.Fn sigignore +function sets the disposition of +.Fa sig +to +.Dv SIG_IGN . +.Pp +The +.Fn xsi_sigpause +function removes +.Fa sig +from the signal mask of the calling process and suspend the calling process +until a signal is received. +The +.Fn xsi_sigpause +function restores the signal mask of the process to its original state before +returning. .Pp The .Fn sigpause @@ -57,13 +154,47 @@ The argument is usually 0 to indicate that no signals are to be blocked. +.Sh RETURN VALUES The .Fn sigpause -function -always terminates by being interrupted, returning -1 with +and +.Fn xsi_sigpause +functions +always terminate by being interrupted, returning -1 with .Va errno set to -.Er EINTR +.Er EINTR . +.Pp +Upon successful completion, +.Fn sigset +returns +.Dv SIG_HOLD +if the signal had been blocked and the signal's previous disposition if +it had not been blocked. +Otherwise, +.Dv SIG_ERR is returned and +.Va errno +set to indicate the error. +.Pp +For all other functions, upon successful completion, 0 is returned. +Otherwise, -1 is returned and +.Va errno +is set to indicate the error: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa sig +argument +is not a valid signal number. +.It Bq Er EINVAL +For +.Fn sigset +and +.Fn sigignore +functions, an attempt was made to catch or ignore +.Dv SIGKILL +or +.Dv SIGSTOP . .Sh SEE ALSO .Xr kill 2 , .Xr sigaction 2 , @@ -85,9 +216,26 @@ and was copied from there into the .Pq Tn XSI option of .St -p1003.1-2001 . +.Fx +implements it under the name +.Fn xsi_sigpause . +The +.Fn sighold , +.Fn sigignore , +.Fn sigrelse +and +.Fn sigset +functions are implemented for compatibility with +.Sy System V +and +.Sy XSI +interfaces. .Sh HISTORY The .Fn sigpause function appeared in .Bx 4.2 and has been deprecated. +All other functions appeared in +.Fx 9.0 +and were deprecated before being implemented. -- cgit v1.1 From b0e5c93d265f054fc567475798ffca846854d375 Mon Sep 17 00:00:00 2001 From: jh Date: Thu, 26 Nov 2009 19:09:10 +0000 Subject: Clarify that the value of the fts_info field is different in post-order. Discussed with: das Approved by: trasz (mentor) MFC after: 1 week --- lib/libc/gen/fts.3 | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/fts.3 b/lib/libc/gen/fts.3 index dfe2de0..4b05157 100644 --- a/lib/libc/gen/fts.3 +++ b/lib/libc/gen/fts.3 @@ -28,7 +28,7 @@ .\" @(#)fts.3 8.5 (Berkeley) 4/16/94 .\" $FreeBSD$ .\" -.Dd October 5, 2009 +.Dd November 25, 2009 .Dt FTS 3 .Os .Sh NAME @@ -198,10 +198,9 @@ A directory being visited in post-order. The contents of the .Vt FTSENT structure will be unchanged from when -it was returned in pre-order, i.e., with the +the directory was visited in pre-order, except for the .Fa fts_info -field set to -.Dv FTS_D . +field. .It Dv FTS_ERR This is an error return, and the .Fa fts_errno -- cgit v1.1 From 9d7cf052cd6d24448402e219eb3edf32a8516f4b Mon Sep 17 00:00:00 2001 From: jh Date: Thu, 26 Nov 2009 19:11:44 +0000 Subject: Reset path name back to original correctly in fts_build() when FTS_NOCHDIR option is used. fts_build() could strip a trailing slash from path name in post-order visit if a path pointing to an empty directory was given for fts_open(). PR: bin/133907, kern/134513 Reviewed by: das Approved by: trasz (mentor) MFC after: 1 month --- lib/libc/gen/fts.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c index 392bda9..1c547a1 100644 --- a/lib/libc/gen/fts.c +++ b/lib/libc/gen/fts.c @@ -842,11 +842,8 @@ mem1: saved_errno = errno; * If not changing directories, reset the path back to original * state. */ - if (ISSET(FTS_NOCHDIR)) { - if (len == sp->fts_pathlen || nitems == 0) - --cp; - *cp = '\0'; - } + if (ISSET(FTS_NOCHDIR)) + sp->fts_path[cur->fts_pathlen] = '\0'; /* * If descended after called from fts_children or after called from -- cgit v1.1 From 6909f7535ebfa64618eff12fc2bb071dde06a52b Mon Sep 17 00:00:00 2001 From: ed Date: Fri, 27 Nov 2009 13:05:14 +0000 Subject: Properly use the envp argument in execvPe(). execvPe() is called by _execvpe(), which we added to implement posix_spawnp(). We just took execvP() and added the envp argument. Unfortunately we forgot to change the implementation to use envp over environ. This fixes the following piece of code: | char * const arg[2] = { "env", NULL }; | char * const env[2] = { "FOO=BAR", NULL }; | posix_spawnp(NULL, "/usr/bin/env", NULL, NULL, arg, env); MFC after: 2 weeks --- lib/libc/gen/exec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/exec.c b/lib/libc/gen/exec.c index 985a09a..7ffce90 100644 --- a/lib/libc/gen/exec.c +++ b/lib/libc/gen/exec.c @@ -209,7 +209,7 @@ execvPe(name, path, argv, envp) bcopy(name, buf + lp + 1, ln); buf[lp + ln + 1] = '\0'; -retry: (void)_execve(bp, argv, environ); +retry: (void)_execve(bp, argv, envp); switch (errno) { case E2BIG: goto done; @@ -228,7 +228,7 @@ retry: (void)_execve(bp, argv, environ); memp[0] = "sh"; memp[1] = bp; bcopy(argv + 1, memp + 2, cnt * sizeof(char *)); - (void)_execve(_PATH_BSHELL, memp, environ); + (void)_execve(_PATH_BSHELL, memp, envp); goto done; case ENOMEM: goto done; -- cgit v1.1 From 6729ce6df0a2aaff5798f68f0005adf4b5271fca Mon Sep 17 00:00:00 2001 From: danger Date: Sat, 28 Nov 2009 11:27:37 +0000 Subject: - correct xref sections PR: docs/140940 Submitted by: Bruce Cran MFC after: 1 week --- lib/libc/net/sctp_send.3 | 2 +- lib/libc/net/sctp_sendmsg.3 | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/net/sctp_send.3 b/lib/libc/net/sctp_send.3 index 2301730..2191ea1 100644 --- a/lib/libc/net/sctp_send.3 +++ b/lib/libc/net/sctp_send.3 @@ -111,7 +111,7 @@ The argument is an opaque 32 bit value that is passed transparently through the stack to the peer endpoint. It will be available on reception of a message (see -.Xr sctp_recvmsg 2 ) . +.Xr sctp_recvmsg 3 ) . Note that the stack passes this value without regard to byte order. .Pp diff --git a/lib/libc/net/sctp_sendmsg.3 b/lib/libc/net/sctp_sendmsg.3 index 61eec22..6c48d5e 100644 --- a/lib/libc/net/sctp_sendmsg.3 +++ b/lib/libc/net/sctp_sendmsg.3 @@ -103,13 +103,13 @@ is set to the message is not transmitted. .Pp No indication of failure to deliver is implicit in a -.Xr sctp_sendmsg 2 +.Xr sctp_sendmsg 3 call. Locally detected errors are indicated by a return value of -1. .Pp If no space is available at the socket to hold the message to be transmitted, then -.Xr sctp_sendmsg 2 +.Xr sctp_sendmsg 3 normally blocks, unless the socket has been placed in non-blocking I/O mode. The @@ -123,7 +123,7 @@ argument is an opaque 32 bit value that is passed transparently through the stack to the peer endpoint. It will be available on reception of a message (see -.Xr sctp_recvmsg 2 ) . +.Xr sctp_recvmsg 3 ) . Note that the stack passes this value without regard to byte order. .Pp -- cgit v1.1 From 32cc2b56a77bafdbaa36b298213654cc42281683 Mon Sep 17 00:00:00 2001 From: green Date: Tue, 1 Dec 2009 05:04:31 +0000 Subject: Do not gratuitously fail *env(3) operations due to corrupt ('='-less) **environ entries. This puts non-getenv(3) operations in line with getenv(3) in that bad environ entries do not cause all operations to fail. There is still some inconsistency in that getenv(3) in the absence of any environment-modifying operation does not emit corrupt environ entry warnings. I also fixed another inconsistency in getenv(3) where updating the global environ pointer would not be reflected in the return values. It would have taken an intermediary setenv(3)/putenv(3)/unsetenv(3) in order to see the change. --- lib/libc/stdlib/getenv.c | 64 +++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 28 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdlib/getenv.c b/lib/libc/stdlib/getenv.c index 2abf7fc..810e671 100644 --- a/lib/libc/stdlib/getenv.c +++ b/lib/libc/stdlib/getenv.c @@ -96,6 +96,8 @@ static int envVarsTotal = 0; /* Deinitialization of new environment. */ static void __attribute__ ((destructor)) __clean_env_destructor(void); +/* Resetting the environ pointer will affect the env functions. */ +static int __merge_environ(void); /* @@ -190,6 +192,9 @@ __findenv_environ(const char *name, size_t nameLen) { int envNdx; + if (environ == NULL) + return (NULL); + /* Find variable within environ. */ for (envNdx = 0; environ[envNdx] != NULL; envNdx++) if (strncmpeq(environ[envNdx], name, nameLen)) @@ -328,6 +333,7 @@ __build_env(void) { char **env; int activeNdx; + int checking; int envNdx; int savedErrno; size_t nameLen; @@ -339,6 +345,23 @@ __build_env(void) /* Count environment variables. */ for (env = environ, envVarsTotal = 0; *env != NULL; env++) envVarsTotal++; + /* Remove any corrupt variable entries, but do not error out. */ + checking = 0; + while (checking < envVarsTotal) { + if (strchr(environ[checking], '=') != NULL) { + checking++; + } else { + __env_warnx(CorruptEnvValueMsg, + environ[checking], strlen(environ[checking])); + /* + * Pull back all remaining entries from checking + 1 + * through envVarsTotal, including the NULL at the end. + */ + memmove(&environ[checking], &environ[checking + 1], + sizeof(char *) * (envVarsTotal - checking)); + envVarsTotal--; + } + } envVarsSize = envVarsTotal * 2; /* Create new environment. */ @@ -353,18 +376,8 @@ __build_env(void) strdup(environ[envVarsTotal - envNdx - 1]); if (envVars[envNdx].name == NULL) goto Failure; - envVars[envNdx].value = strchr(envVars[envNdx].name, '='); - if (envVars[envNdx].value != NULL) { - envVars[envNdx].value++; - envVars[envNdx].valueSize = - strlen(envVars[envNdx].value); - } else { - __env_warnx(CorruptEnvValueMsg, envVars[envNdx].name, - strlen(envVars[envNdx].name)); - errno = EFAULT; - goto Failure; - } - + envVars[envNdx].value = strchr(envVars[envNdx].name, '=') + 1; + envVars[envNdx].valueSize = strlen(envVars[envNdx].value); /* * Find most current version of variable to make active. This * will prevent multiple active variables from being created @@ -426,22 +439,18 @@ getenv(const char *name) } /* - * An empty environment (environ or its first value) regardless if - * environ has been copied before will return a NULL. - * - * If the environment is not empty, find an environment variable via - * environ if environ has not been copied via an *env() call or been - * replaced by a running program, otherwise, use the rebuilt - * environment. + * If we have not already allocated memory by performing + * write operations on the environment, avoid doing so now. */ - if (environ == NULL || environ[0] == NULL) - return (NULL); - else if (envVars == NULL || environ != intEnviron) + if (envVars == NULL) return (__findenv_environ(name, nameLen)); - else { - envNdx = envVarsTotal - 1; - return (__findenv(name, nameLen, &envNdx, true)); - } + + /* Synchronize environment. */ + if (__merge_environ() == -1) + return (NULL); + + envNdx = envVarsTotal - 1; + return (__findenv(name, nameLen, &envNdx, true)); } @@ -559,8 +568,7 @@ __merge_environ(void) if ((equals = strchr(*env, '=')) == NULL) { __env_warnx(CorruptEnvValueMsg, *env, strlen(*env)); - errno = EFAULT; - return (-1); + continue; } if (__setenv(*env, equals - *env, equals + 1, 1) == -1) -- cgit v1.1 From 60a1c9a9096f7bbc1764a65206c39084b6541337 Mon Sep 17 00:00:00 2001 From: keramida Date: Tue, 1 Dec 2009 06:12:31 +0000 Subject: Describe what setpgid(2) does when pgid=0. The text has been copied from NetBSD's manpage, and it also matches the behavior described by the Open Group's online copy of setpgid.2 at http://www.opengroup.org/onlinepubs/009695399/functions/setpgid.html Obtained from: NetBSD Submitted by: Petros Barbayiannis MFC after: 1 week --- lib/libc/sys/setpgid.2 | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/sys/setpgid.2 b/lib/libc/sys/setpgid.2 index a56d831..4ad89de 100644 --- a/lib/libc/sys/setpgid.2 +++ b/lib/libc/sys/setpgid.2 @@ -54,6 +54,11 @@ to the specified If .Fa pid is zero, then the call applies to the current process. +If +.Fa pgrp +is zero, then the process id of the process specified by +.Fa pid +is used instead. .Pp If the affected process is not the invoking process, then it must be a child of the invoking process, it must not have performed an -- cgit v1.1 From 6d6c10fa2660837067111baa276a9ddb2bcc8785 Mon Sep 17 00:00:00 2001 From: green Date: Tue, 1 Dec 2009 06:42:47 +0000 Subject: Temporarily revert the previous change because the linker has been modified so that it will abort when the environment is bad. --- lib/libc/stdlib/getenv.c | 64 +++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 36 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdlib/getenv.c b/lib/libc/stdlib/getenv.c index 810e671..2abf7fc 100644 --- a/lib/libc/stdlib/getenv.c +++ b/lib/libc/stdlib/getenv.c @@ -96,8 +96,6 @@ static int envVarsTotal = 0; /* Deinitialization of new environment. */ static void __attribute__ ((destructor)) __clean_env_destructor(void); -/* Resetting the environ pointer will affect the env functions. */ -static int __merge_environ(void); /* @@ -192,9 +190,6 @@ __findenv_environ(const char *name, size_t nameLen) { int envNdx; - if (environ == NULL) - return (NULL); - /* Find variable within environ. */ for (envNdx = 0; environ[envNdx] != NULL; envNdx++) if (strncmpeq(environ[envNdx], name, nameLen)) @@ -333,7 +328,6 @@ __build_env(void) { char **env; int activeNdx; - int checking; int envNdx; int savedErrno; size_t nameLen; @@ -345,23 +339,6 @@ __build_env(void) /* Count environment variables. */ for (env = environ, envVarsTotal = 0; *env != NULL; env++) envVarsTotal++; - /* Remove any corrupt variable entries, but do not error out. */ - checking = 0; - while (checking < envVarsTotal) { - if (strchr(environ[checking], '=') != NULL) { - checking++; - } else { - __env_warnx(CorruptEnvValueMsg, - environ[checking], strlen(environ[checking])); - /* - * Pull back all remaining entries from checking + 1 - * through envVarsTotal, including the NULL at the end. - */ - memmove(&environ[checking], &environ[checking + 1], - sizeof(char *) * (envVarsTotal - checking)); - envVarsTotal--; - } - } envVarsSize = envVarsTotal * 2; /* Create new environment. */ @@ -376,8 +353,18 @@ __build_env(void) strdup(environ[envVarsTotal - envNdx - 1]); if (envVars[envNdx].name == NULL) goto Failure; - envVars[envNdx].value = strchr(envVars[envNdx].name, '=') + 1; - envVars[envNdx].valueSize = strlen(envVars[envNdx].value); + envVars[envNdx].value = strchr(envVars[envNdx].name, '='); + if (envVars[envNdx].value != NULL) { + envVars[envNdx].value++; + envVars[envNdx].valueSize = + strlen(envVars[envNdx].value); + } else { + __env_warnx(CorruptEnvValueMsg, envVars[envNdx].name, + strlen(envVars[envNdx].name)); + errno = EFAULT; + goto Failure; + } + /* * Find most current version of variable to make active. This * will prevent multiple active variables from being created @@ -439,18 +426,22 @@ getenv(const char *name) } /* - * If we have not already allocated memory by performing - * write operations on the environment, avoid doing so now. + * An empty environment (environ or its first value) regardless if + * environ has been copied before will return a NULL. + * + * If the environment is not empty, find an environment variable via + * environ if environ has not been copied via an *env() call or been + * replaced by a running program, otherwise, use the rebuilt + * environment. */ - if (envVars == NULL) - return (__findenv_environ(name, nameLen)); - - /* Synchronize environment. */ - if (__merge_environ() == -1) + if (environ == NULL || environ[0] == NULL) return (NULL); - - envNdx = envVarsTotal - 1; - return (__findenv(name, nameLen, &envNdx, true)); + else if (envVars == NULL || environ != intEnviron) + return (__findenv_environ(name, nameLen)); + else { + envNdx = envVarsTotal - 1; + return (__findenv(name, nameLen, &envNdx, true)); + } } @@ -568,7 +559,8 @@ __merge_environ(void) if ((equals = strchr(*env, '=')) == NULL) { __env_warnx(CorruptEnvValueMsg, *env, strlen(*env)); - continue; + errno = EFAULT; + return (-1); } if (__setenv(*env, equals - *env, equals + 1, 1) == -1) -- cgit v1.1 From 3c3bf7569ef5da9014f27c65c577f5db3c4d803d Mon Sep 17 00:00:00 2001 From: brueffer Date: Tue, 1 Dec 2009 07:28:56 +0000 Subject: Add an .Nm for strncat. PR: 141037 Submitted by: Jeremy Huddleston MFC after: 3 days --- lib/libc/string/strcat.3 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/string/strcat.3 b/lib/libc/string/strcat.3 index 0290994..4c9fec9 100644 --- a/lib/libc/string/strcat.3 +++ b/lib/libc/string/strcat.3 @@ -32,11 +32,12 @@ .\" @(#)strcat.3 8.1 (Berkeley) 6/4/93 .\" $FreeBSD$ .\" -.Dd June 4, 1993 +.Dd December 1, 2009 .Dt STRCAT 3 .Os .Sh NAME -.Nm strcat +.Nm strcat , +.Nm strncat .Nd concatenate strings .Sh LIBRARY .Lb libc -- cgit v1.1 From 78cff0361bc897ea25a0b90fc331bb2493be8e11 Mon Sep 17 00:00:00 2001 From: brueffer Date: Wed, 2 Dec 2009 07:51:25 +0000 Subject: Fix the dprintf() prototype. PR: 141087 Submitted by: Jeremy Huddleston MFC after: 3 days --- lib/libc/stdio/printf.3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdio/printf.3 b/lib/libc/stdio/printf.3 index 27d5bf0..2587aa2 100644 --- a/lib/libc/stdio/printf.3 +++ b/lib/libc/stdio/printf.3 @@ -32,7 +32,7 @@ .\" @(#)printf.3 8.1 (Berkeley) 6/4/93 .\" $FreeBSD$ .\" -.Dd March 3, 2009 +.Dd December 2, 2009 .Dt PRINTF 3 .Os .Sh NAME @@ -55,7 +55,7 @@ .Ft int .Fn asprintf "char **ret" "const char *format" ... .Ft int -.Fn dprintf "int" "const char * restrict format" ... +.Fn dprintf "int fd" "const char * restrict format" ... .In stdarg.h .Ft int .Fn vprintf "const char * restrict format" "va_list ap" -- cgit v1.1 From b6cdcc994062fb93affd9d473219a5f06d4029ff Mon Sep 17 00:00:00 2001 From: jhb Date: Thu, 3 Dec 2009 15:14:30 +0000 Subject: The fd_mask type is an unsigned long, not an int, so treat the mask as a long instead of an int when examining the results of select() to look for RPC requests. Previously this routine would ignore RPC requests to sockets whose file descriptor mod 64 was greater than 31 on a 64-bit platform. PR: amd64/141130 Submitted by: liujb of array networks MFC after: 3 days --- lib/libc/rpc/svc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/rpc/svc.c b/lib/libc/rpc/svc.c index d205121..282c2be 100644 --- a/lib/libc/rpc/svc.c +++ b/lib/libc/rpc/svc.c @@ -627,8 +627,8 @@ svc_getreqset(readfds) maskp = readfds->fds_bits; for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) { - for (mask = *maskp++; (bit = ffs(mask)) != 0; - mask ^= (1 << (bit - 1))) { + for (mask = *maskp++; (bit = ffsl(mask)) != 0; + mask ^= (1ul << (bit - 1))) { /* sock has input waiting */ fd = sock + bit - 1; svc_getreq_common(fd); -- cgit v1.1 From 786e403e1b7494ee608c7cedc7d663161751a200 Mon Sep 17 00:00:00 2001 From: gabor Date: Thu, 3 Dec 2009 19:27:12 +0000 Subject: - Update the Spanish NLS catalog Reviewed by: carvay, the.infamous.paul@gmail.com, Joan Picanyol i Puig , Ing . Marcos Luis Ortiz Valmaseda , eskanete@gmail.com, Jose M Rodriguez , Guillermo Hernandez , dani.doni@gmail.com --- lib/libc/nls/es_ES.ISO8859-1.msg | 56 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 5 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/nls/es_ES.ISO8859-1.msg b/lib/libc/nls/es_ES.ISO8859-1.msg index 8fc9c7d..2687c17 100644 --- a/lib/libc/nls/es_ES.ISO8859-1.msg +++ b/lib/libc/nls/es_ES.ISO8859-1.msg @@ -62,7 +62,7 @@ $ EFBIG $ ENOSPC 28 No queda espacio libre en el dispositivo $ ESPIPE -29 Illegal seek +29 Bsqueda ilegal $ EROFS 30 Sistema de ficheros de solo lectura $ EMLINK @@ -88,7 +88,7 @@ $ EMSGSIZE $ EPROTOTYPE 41 Tipo errneo de protocolo para el socket $ ENOPROTOOPT -42 protocolo no disponible +42 Protocolo no disponible $ EPROTONOSUPPORT 43 Protocolo no contemplado $ ESOCKTNOSUPPORT @@ -176,23 +176,33 @@ $ EOVERFLOW $ ECANCELED 85 Operacin cancelada $ EILSEQ -86 Illegal byte sequence +86 Secuencia de bytes ilegal $ ENOATTR 87 Atributo no encontrado $ EDOOFUS 88 Error de programacin +$ EBADMSG +89 Mensaje invlido +$ EMULTIHOP +90 Intento de hop multiple +$ ENOLINK +91 El enlace se ha roto +$ EPROTO +92 Fallo de protocolo +$ ENOTCAPABLE +93 Habilidades insuficientes $ $ strsignal() support catalog $ $set 2 $ SIGHUP -1 Fn de lnea (Hangup) +1 Fin de lnea (Hangup) $ SIGINT 2 Interrumpido $ SIGQUIT 3 Terminado $ SIGILL -4 Illegal instruction +4 Instruccin ilegal $ SIGTRAP 5 Trace/BPT trap $ SIGABRT @@ -247,3 +257,39 @@ $ SIGUSR1 30 Seal definida por el usuario n1 $ SIGUSR2 31 Seal definida por el usuario n2 +$ +$ gai_strerror() support catalog +$ +$set 3 +$ 1 (obsoleto) +1 Tipo de direccin no contemplado +$ EAI_AGAIN +2 Error transitorio en la resolucin de nombres +$ EAI_BADFLAGS +3 Valor invlido de ai_flags +$ EAI_FAIL +4 Error no recuperable en la resolucin de nombres +$ EAI_FAMILY +5 ai_family no contemplado +$ EAI_MEMORY +6 Error en la asignacin de memoria +$ 7 (obsoleto) +7 No hay direccin asociada con el nombre de mquina +$ EAI_NONAME +8 No se dispone nombre de mquina, ni nombre de servicio +$ EAI_SERVICE +9 Nombre de servicio no contemplado en ai_socktype +$ EAI_SOCKTYPE +10 ai_socktype no contemplado +$ EAI_SYSTEM +11 Error de sistema devuelto en errno +$ EAI_BADHINTS +12 Valor invlido de hints +$ EAI_PROTOCOL +13 Protocolo resuelto desconocido +$ EAI_OVERFLOW +14 Bfer de argumentos sobrepasado +$ 0 +32766 xito +$ NL_MSGMAX +32767 Error desconocido -- cgit v1.1 From 50b1bbf2fabc2ff1b380951bfb5e5f7a12c36589 Mon Sep 17 00:00:00 2001 From: trhodes Date: Fri, 4 Dec 2009 09:20:20 +0000 Subject: Add a missing word to a sentence in the return values section. --- lib/libc/string/strcmp.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/string/strcmp.3 b/lib/libc/string/strcmp.3 index 1e13ed8..74d1a5c 100644 --- a/lib/libc/string/strcmp.3 +++ b/lib/libc/string/strcmp.3 @@ -75,7 +75,7 @@ The .Fn strcmp and .Fn strncmp -return an integer greater than, equal to, or less than 0, according +functions return an integer greater than, equal to, or less than 0, according as the string .Fa s1 is greater than, equal to, or less than the string -- cgit v1.1 From 8b25a2a3d0bfd8d257a705d527d9a83fb4ef95bf Mon Sep 17 00:00:00 2001 From: ed Date: Sat, 5 Dec 2009 18:51:44 +0000 Subject: Remove (hidden) warning about missing prototypes for fdevname(3). --- lib/libc/gen/fdevname.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/libc') diff --git a/lib/libc/gen/fdevname.c b/lib/libc/gen/fdevname.c index be235f7..d60da70 100644 --- a/lib/libc/gen/fdevname.c +++ b/lib/libc/gen/fdevname.c @@ -30,6 +30,7 @@ __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include +#include #include "un-namespace.h" char * -- cgit v1.1 From ad8df7188303ece150047f991982d50ffe9659a4 Mon Sep 17 00:00:00 2001 From: ed Date: Sat, 5 Dec 2009 18:53:04 +0000 Subject: Use ANSI C prototypes inside termios. While there, add a missing __unused to hide a warning in tcsetbreak(). --- lib/libc/gen/termios.c | 44 +++++++++++++------------------------------- 1 file changed, 13 insertions(+), 31 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/termios.c b/lib/libc/gen/termios.c index 85ca4e3..fc21757 100644 --- a/lib/libc/gen/termios.c +++ b/lib/libc/gen/termios.c @@ -45,18 +45,14 @@ __FBSDID("$FreeBSD$"); #include "un-namespace.h" int -tcgetattr(fd, t) - int fd; - struct termios *t; +tcgetattr(int fd, struct termios *t) { return (_ioctl(fd, TIOCGETA, t)); } int -tcsetattr(fd, opt, t) - int fd, opt; - const struct termios *t; +tcsetattr(int fd, int opt, const struct termios *t) { struct termios localterm; @@ -88,8 +84,7 @@ tcsetpgrp(int fd, pid_t pgrp) } pid_t -tcgetpgrp(fd) - int fd; +tcgetpgrp(int fd) { int s; @@ -123,25 +118,21 @@ tcsetsid(int fd, pid_t pid) } speed_t -cfgetospeed(t) - const struct termios *t; +cfgetospeed(const struct termios *t) { return (t->c_ospeed); } speed_t -cfgetispeed(t) - const struct termios *t; +cfgetispeed(const struct termios *t) { return (t->c_ispeed); } int -cfsetospeed(t, speed) - struct termios *t; - speed_t speed; +cfsetospeed(struct termios *t, speed_t speed) { t->c_ospeed = speed; @@ -149,9 +140,7 @@ cfsetospeed(t, speed) } int -cfsetispeed(t, speed) - struct termios *t; - speed_t speed; +cfsetispeed(struct termios *t, speed_t speed) { t->c_ispeed = speed; @@ -159,9 +148,7 @@ cfsetispeed(t, speed) } int -cfsetspeed(t, speed) - struct termios *t; - speed_t speed; +cfsetspeed(struct termios *t, speed_t speed) { t->c_ispeed = t->c_ospeed = speed; @@ -173,8 +160,7 @@ cfsetspeed(t, speed) * mode with no characters interpreted, 8-bit data path. */ void -cfmakeraw(t) - struct termios *t; +cfmakeraw(struct termios *t) { t->c_iflag &= ~(IMAXBEL|IXOFF|INPCK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IGNPAR); @@ -188,8 +174,7 @@ cfmakeraw(t) } int -tcsendbreak(fd, len) - int fd, len; +tcsendbreak(int fd, int len __unused) { struct timeval sleepytime; @@ -204,8 +189,7 @@ tcsendbreak(fd, len) } int -__tcdrain(fd) - int fd; +__tcdrain(int fd) { return (_ioctl(fd, TIOCDRAIN, 0)); } @@ -214,8 +198,7 @@ __weak_reference(__tcdrain, tcdrain); __weak_reference(__tcdrain, _tcdrain); int -tcflush(fd, which) - int fd, which; +tcflush(int fd, int which) { int com; @@ -237,8 +220,7 @@ tcflush(fd, which) } int -tcflow(fd, action) - int fd, action; +tcflow(int fd, int action) { struct termios term; u_char c; -- cgit v1.1 From 1a90ab9d6e33a9a1598646aa6c7bce084c7217cf Mon Sep 17 00:00:00 2001 From: ed Date: Sat, 5 Dec 2009 18:55:16 +0000 Subject: Remove warnings from exec.c. The entries in the argv array are not const themselves, but sometimes we want to fill in const values. Just make the array const and use __DECONST() to make it const for the execve()-call itself. Also convert the only K&R prototype to ANSI. --- lib/libc/gen/exec.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/exec.c b/lib/libc/gen/exec.c index 7ffce90..b83136e 100644 --- a/lib/libc/gen/exec.c +++ b/lib/libc/gen/exec.c @@ -54,7 +54,7 @@ int execl(const char *name, const char *arg, ...) { va_list ap; - char **argv; + const char **argv; int n; va_start(ap, arg); @@ -69,18 +69,19 @@ execl(const char *name, const char *arg, ...) } va_start(ap, arg); n = 1; - argv[0] = (char *)arg; + argv[0] = arg; while ((argv[n] = va_arg(ap, char *)) != NULL) n++; va_end(ap); - return (_execve(name, argv, environ)); + return (_execve(name, __DECONST(char **, argv), environ)); } int execle(const char *name, const char *arg, ...) { va_list ap; - char **argv, **envp; + const char **argv; + char **envp; int n; va_start(ap, arg); @@ -95,19 +96,19 @@ execle(const char *name, const char *arg, ...) } va_start(ap, arg); n = 1; - argv[0] = (char *)arg; + argv[0] = arg; while ((argv[n] = va_arg(ap, char *)) != NULL) n++; envp = va_arg(ap, char **); va_end(ap); - return (_execve(name, argv, envp)); + return (_execve(name, __DECONST(char **, argv), envp)); } int execlp(const char *name, const char *arg, ...) { va_list ap; - char **argv; + const char **argv; int n; va_start(ap, arg); @@ -122,11 +123,11 @@ execlp(const char *name, const char *arg, ...) } va_start(ap, arg); n = 1; - argv[0] = (char *)arg; + argv[0] = arg; while ((argv[n] = va_arg(ap, char *)) != NULL) n++; va_end(ap); - return (execvp(name, argv)); + return (execvp(name, __DECONST(char **, argv))); } int @@ -145,24 +146,21 @@ execvp(const char *name, char * const *argv) } static int -execvPe(name, path, argv, envp) - const char *name; - const char *path; - char * const *argv; - char * const *envp; +execvPe(const char *name, const char *path, char * const *argv, + char * const *envp) { - char **memp; - int cnt, lp, ln; - char *p; + const char **memp; + size_t cnt, lp, ln; int eacces, save_errno; - char *bp, *cur, buf[MAXPATHLEN]; + char *cur, buf[MAXPATHLEN]; + const char *p, *bp; struct stat sb; eacces = 0; /* If it's an absolute or relative path name, it's easy. */ if (index(name, '/')) { - bp = (char *)name; + bp = name; cur = NULL; goto retry; } @@ -228,7 +226,8 @@ retry: (void)_execve(bp, argv, envp); memp[0] = "sh"; memp[1] = bp; bcopy(argv + 1, memp + 2, cnt * sizeof(char *)); - (void)_execve(_PATH_BSHELL, memp, envp); + (void)_execve(_PATH_BSHELL, + __DECONST(char **, memp), envp); goto done; case ENOMEM: goto done; -- cgit v1.1 From e912442e98904e4d3d77ac344f9a353688ca3e9f Mon Sep 17 00:00:00 2001 From: ed Date: Sat, 5 Dec 2009 19:04:21 +0000 Subject: Don't let the C library depend on . The maximum length of a username has nothing to do with the size of the username in the utmp files. Use MAXLOGNAME, which is defined as 17 (UT_USERSIZE + 1). --- lib/libc/gen/getlogin.c | 1 - lib/libc/gen/pwcache.c | 18 +++++++++--------- lib/libc/posix1e/acl_to_text.c | 7 +++---- 3 files changed, 12 insertions(+), 14 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/getlogin.c b/lib/libc/gen/getlogin.c index dc85d3a..569cf42 100644 --- a/lib/libc/gen/getlogin.c +++ b/lib/libc/gen/getlogin.c @@ -36,7 +36,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include diff --git a/lib/libc/gen/pwcache.c b/lib/libc/gen/pwcache.c index 501d6ba..a8a73f1 100644 --- a/lib/libc/gen/pwcache.c +++ b/lib/libc/gen/pwcache.c @@ -33,13 +33,13 @@ static char sccsid[] = "@(#)pwcache.c 8.1 (Berkeley) 6/4/93"; #include __FBSDID("$FreeBSD$"); +#include #include #include #include #include #include -#include #define NCACHE 64 /* power of 2 */ #define MASK (NCACHE - 1) /* bits to store with */ @@ -50,7 +50,7 @@ user_from_uid(uid_t uid, int nouser) static struct ncache { uid_t uid; int found; - char name[UT_NAMESIZE + 1]; + char name[MAXLOGNAME]; } c_uid[NCACHE]; static int pwopen; struct passwd *pw; @@ -66,11 +66,11 @@ user_from_uid(uid_t uid, int nouser) cp->uid = uid; if (pw != NULL) { cp->found = 1; - (void)strncpy(cp->name, pw->pw_name, UT_NAMESIZE); - cp->name[UT_NAMESIZE] = '\0'; + (void)strncpy(cp->name, pw->pw_name, MAXLOGNAME - 1); + cp->name[MAXLOGNAME - 1] = '\0'; } else { cp->found = 0; - (void)snprintf(cp->name, UT_NAMESIZE, "%u", uid); + (void)snprintf(cp->name, MAXLOGNAME - 1, "%u", uid); if (nouser) return (NULL); } @@ -84,7 +84,7 @@ group_from_gid(gid_t gid, int nogroup) static struct ncache { gid_t gid; int found; - char name[UT_NAMESIZE + 1]; + char name[MAXLOGNAME]; } c_gid[NCACHE]; static int gropen; struct group *gr; @@ -100,11 +100,11 @@ group_from_gid(gid_t gid, int nogroup) cp->gid = gid; if (gr != NULL) { cp->found = 1; - (void)strncpy(cp->name, gr->gr_name, UT_NAMESIZE); - cp->name[UT_NAMESIZE] = '\0'; + (void)strncpy(cp->name, gr->gr_name, MAXLOGNAME - 1); + cp->name[MAXLOGNAME - 1] = '\0'; } else { cp->found = 0; - (void)snprintf(cp->name, UT_NAMESIZE, "%u", gid); + (void)snprintf(cp->name, MAXLOGNAME - 1, "%u", gid); if (nogroup) return (NULL); } diff --git a/lib/libc/posix1e/acl_to_text.c b/lib/libc/posix1e/acl_to_text.c index 79a950a..e5fd1f7 100644 --- a/lib/libc/posix1e/acl_to_text.c +++ b/lib/libc/posix1e/acl_to_text.c @@ -39,7 +39,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include "acl_support.h" @@ -58,7 +57,7 @@ _posix1e_acl_to_text(acl_t acl, ssize_t *len_p, int flags) { struct acl *acl_int; char *buf, *tmpbuf; - char name_buf[UT_NAMESIZE+1]; + char name_buf[MAXLOGNAME]; char perm_buf[_POSIX1E_ACL_STRING_PERM_MAXSIZE+1], effective_perm_buf[_POSIX1E_ACL_STRING_PERM_MAXSIZE+1]; int i, error, len; @@ -103,7 +102,7 @@ _posix1e_acl_to_text(acl_t acl, ssize_t *len_p, int flags) goto error_label; error = _posix1e_acl_id_to_name(ae_tag, ae_id, - UT_NAMESIZE+1, name_buf, flags); + MAXLOGNAME, name_buf, flags); if (error) goto error_label; @@ -163,7 +162,7 @@ _posix1e_acl_to_text(acl_t acl, ssize_t *len_p, int flags) goto error_label; error = _posix1e_acl_id_to_name(ae_tag, ae_id, - UT_NAMESIZE+1, name_buf, flags); + MAXLOGNAME, name_buf, flags); if (error) goto error_label; -- cgit v1.1 From 06fcc20479dbea7b80fde60d667c7455ca58c451 Mon Sep 17 00:00:00 2001 From: ed Date: Sat, 5 Dec 2009 19:31:38 +0000 Subject: Fix many "function declaration isn't a prototype" warnings in libc. I've only fixed code that seems to be written by `us'. There are still many warnings like this present in resolv/, rpc/, stdtime/ and yp/. --- lib/libc/gen/getttyent.c | 26 ++++++++++---------------- lib/libc/gen/nlist.c | 3 +-- lib/libc/gen/pause.c | 2 +- lib/libc/gen/raise.c | 3 +-- lib/libc/gen/sleep.c | 3 +-- lib/libc/gen/timezone.c | 10 +++------- lib/libc/gen/usleep.c | 3 +-- lib/libc/gmon/gmon.c | 2 +- lib/libc/stdio/findfp.c | 2 +- lib/libc/stdio/funopen.c | 10 +++++----- lib/libc/stdlib/system.c | 3 +-- lib/libc/sys/__error.c | 2 +- 12 files changed, 27 insertions(+), 42 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/getttyent.c b/lib/libc/gen/getttyent.c index 9152626..99d9821 100644 --- a/lib/libc/gen/getttyent.c +++ b/lib/libc/gen/getttyent.c @@ -55,8 +55,7 @@ static char *skip(char *); static char *value(char *); struct ttyent * -getttynam(tty) - const char *tty; +getttynam(const char *tty) { struct ttyent *t; @@ -71,7 +70,7 @@ getttynam(tty) } struct ttyent * -getttyent() +getttyent(void) { static struct ttyent tty; static char devpts_name[] = "pts/4294967295"; @@ -178,8 +177,7 @@ getttyent() * the next field. */ static char * -skip(p) - char *p; +skip(char *p) { char *t; int c, q; @@ -212,15 +210,14 @@ skip(p) } static char * -value(p) - char *p; +value(char *p) { return ((p = index(p, '=')) ? ++p : NULL); } int -setttyent() +setttyent(void) { DIR *devpts_dir; @@ -254,7 +251,7 @@ setttyent() } int -endttyent() +endttyent(void) { int rval; @@ -272,9 +269,7 @@ endttyent() } static int -isttystat(tty, flag) - const char *tty; - int flag; +isttystat(const char *tty, int flag) { struct ttyent *t; @@ -283,15 +278,14 @@ isttystat(tty, flag) int -isdialuptty(tty) - const char *tty; +isdialuptty(const char *tty) { return isttystat(tty, TTY_DIALUP); } -int isnettty(tty) - const char *tty; +int +isnettty(const char *tty) { return isttystat(tty, TTY_NETWORK); diff --git a/lib/libc/gen/nlist.c b/lib/libc/gen/nlist.c index 690e0b0..1361af3 100644 --- a/lib/libc/gen/nlist.c +++ b/lib/libc/gen/nlist.c @@ -209,8 +209,7 @@ static void elf_sym_to_nlist(struct nlist *, Elf_Sym *, Elf_Shdr *, int); * as such its use should be restricted. */ int -__elf_is_okay__(ehdr) - Elf_Ehdr *ehdr; +__elf_is_okay__(Elf_Ehdr *ehdr) { int retval = 0; /* diff --git a/lib/libc/gen/pause.c b/lib/libc/gen/pause.c index 86d3643..00bf833 100644 --- a/lib/libc/gen/pause.c +++ b/lib/libc/gen/pause.c @@ -40,7 +40,7 @@ __FBSDID("$FreeBSD$"); * Backwards compatible pause. */ int -__pause() +__pause(void) { return sigpause(sigblock(0L)); } diff --git a/lib/libc/gen/raise.c b/lib/libc/gen/raise.c index 12bd31f..b3d0aae 100644 --- a/lib/libc/gen/raise.c +++ b/lib/libc/gen/raise.c @@ -40,8 +40,7 @@ __weak_reference(__raise, raise); __weak_reference(__raise, _raise); int -__raise(s) - int s; +__raise(int s) { return(kill(getpid(), s)); } diff --git a/lib/libc/gen/sleep.c b/lib/libc/gen/sleep.c index cdf5828..b807c2d 100644 --- a/lib/libc/gen/sleep.c +++ b/lib/libc/gen/sleep.c @@ -41,8 +41,7 @@ __FBSDID("$FreeBSD$"); #include "un-namespace.h" unsigned int -__sleep(seconds) - unsigned int seconds; +__sleep(unsigned int seconds) { struct timespec time_to_sleep; struct timespec time_remaining; diff --git a/lib/libc/gen/timezone.c b/lib/libc/gen/timezone.c index c59ae6b..5f0fa66 100644 --- a/lib/libc/gen/timezone.c +++ b/lib/libc/gen/timezone.c @@ -40,7 +40,7 @@ __FBSDID("$FreeBSD$"); #include #define TZ_MAX_CHARS 255 -char *_tztab(); +char *_tztab(int, int); /* * timezone -- @@ -53,9 +53,7 @@ char *_tztab(); static char czone[TZ_MAX_CHARS]; /* space for zone name */ char * -timezone(zone, dst) - int zone, - dst; +timezone(int zone, int dst) { char *beg, *end; @@ -106,9 +104,7 @@ static struct zone { * STANDARD LIBRARY. */ char * -_tztab(zone,dst) - int zone; - int dst; +_tztab(int zone, int dst) { struct zone *zp; char sign; diff --git a/lib/libc/gen/usleep.c b/lib/libc/gen/usleep.c index 0454665..7d6559b 100644 --- a/lib/libc/gen/usleep.c +++ b/lib/libc/gen/usleep.c @@ -39,8 +39,7 @@ __FBSDID("$FreeBSD$"); #include "un-namespace.h" int -__usleep(useconds) - useconds_t useconds; +__usleep(useconds_t useconds) { struct timespec time_to_sleep; diff --git a/lib/libc/gmon/gmon.c b/lib/libc/gmon/gmon.c index dd85eec..fe769e8 100644 --- a/lib/libc/gmon/gmon.c +++ b/lib/libc/gmon/gmon.c @@ -132,7 +132,7 @@ monstartup(lowpc, highpc) } void -_mcleanup() +_mcleanup(void) { int fd; int fromindex; diff --git a/lib/libc/stdio/findfp.c b/lib/libc/stdio/findfp.c index 586e15c..5bc4af7 100644 --- a/lib/libc/stdio/findfp.c +++ b/lib/libc/stdio/findfp.c @@ -168,7 +168,7 @@ __warn_references(f_prealloc, "warning: this program uses f_prealloc(), which is not recommended."); void -f_prealloc() +f_prealloc(void) { struct glue *g; int n; diff --git a/lib/libc/stdio/funopen.c b/lib/libc/stdio/funopen.c index 9535340..573589f 100644 --- a/lib/libc/stdio/funopen.c +++ b/lib/libc/stdio/funopen.c @@ -42,11 +42,11 @@ __FBSDID("$FreeBSD$"); #include "local.h" FILE * -funopen(cookie, readfn, writefn, seekfn, closefn) - const void *cookie; - int (*readfn)(), (*writefn)(); - fpos_t (*seekfn)(void *cookie, fpos_t off, int whence); - int (*closefn)(); +funopen(const void *cookie, + int (*readfn)(void *, char *, int), + int (*writefn)(void *, const char *, int), + fpos_t (*seekfn)(void *, fpos_t, int), + int (*closefn)(void *)) { FILE *fp; int flags; diff --git a/lib/libc/stdlib/system.c b/lib/libc/stdlib/system.c index 08de630..4f47edf 100644 --- a/lib/libc/stdlib/system.c +++ b/lib/libc/stdlib/system.c @@ -46,8 +46,7 @@ __FBSDID("$FreeBSD$"); #include "libc_private.h" int -__system(command) - const char *command; +__system(const char *command) { pid_t pid, savedpid; int pstat; diff --git a/lib/libc/sys/__error.c b/lib/libc/sys/__error.c index d7b5529..c3f59f8 100644 --- a/lib/libc/sys/__error.c +++ b/lib/libc/sys/__error.c @@ -39,7 +39,7 @@ extern int errno; __weak_reference(__error_unthreaded, __error); int * -__error_unthreaded() +__error_unthreaded(void) { return(&errno); } -- cgit v1.1 From 3a10c0221346669ddb9b9d2f336620cf12c44254 Mon Sep 17 00:00:00 2001 From: scf Date: Sun, 6 Dec 2009 23:05:17 +0000 Subject: Improve the comment within getenv() explaining the search order it takes to find a variable. Include a note that it must not cause the internal environment to be generated since malloc() depends upon getenv(). To call malloc() would create a circular dependency. Recommended by: green Approved by: jilles MFC after: 1 week --- lib/libc/stdlib/getenv.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdlib/getenv.c b/lib/libc/stdlib/getenv.c index 2abf7fc..b7826d7 100644 --- a/lib/libc/stdlib/getenv.c +++ b/lib/libc/stdlib/getenv.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2007-2008 Sean C. Farley + * Copyright (c) 2007-2009 Sean C. Farley * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -160,7 +160,7 @@ __findenv(const char *name, size_t nameLen, int *envNdx, bool onlyActive) /* * Find environment variable from end of array (more likely to be - * active). A variable created by putenv is always active or it is not + * active). A variable created by putenv is always active, or it is not * tracked in the array. */ for (ndx = *envNdx; ndx >= 0; ndx--) @@ -426,13 +426,14 @@ getenv(const char *name) } /* - * An empty environment (environ or its first value) regardless if - * environ has been copied before will return a NULL. + * Variable search order: + * 1. Check for an empty environ. This allows an application to clear + * the environment. + * 2. Search the external environ array. + * 3. Search the internal environment. * - * If the environment is not empty, find an environment variable via - * environ if environ has not been copied via an *env() call or been - * replaced by a running program, otherwise, use the rebuilt - * environment. + * Since malloc() depends upon getenv(), getenv() must never cause the + * internal environment storage to be generated. */ if (environ == NULL || environ[0] == NULL) return (NULL); -- cgit v1.1 From cc8ac328443112ba8c2be9eaa80fc4e9b6e71fa6 Mon Sep 17 00:00:00 2001 From: scf Date: Sun, 6 Dec 2009 23:27:24 +0000 Subject: Change the behavior of setenv(), putenv() and unsetenv() to continue parsing instead of returning an error if a corrupt (not a "name=value" string) entry in the environ array is detected when (re)-building the internal environment. This should prevent applications or libraries from experiencing issues arising from the expectation that these calls will complete even with corrupt entries. The behavior is now as it was prior to 7.0. Reviewed by: jilles MFC after: 1 week --- lib/libc/stdlib/getenv.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdlib/getenv.c b/lib/libc/stdlib/getenv.c index b7826d7..4617f45 100644 --- a/lib/libc/stdlib/getenv.c +++ b/lib/libc/stdlib/getenv.c @@ -361,8 +361,7 @@ __build_env(void) } else { __env_warnx(CorruptEnvValueMsg, envVars[envNdx].name, strlen(envVars[envNdx].name)); - errno = EFAULT; - goto Failure; + continue; } /* @@ -377,8 +376,7 @@ __build_env(void) false) == NULL) { __env_warnx(CorruptEnvFindMsg, envVars[envNdx].name, nameLen); - errno = EFAULT; - goto Failure; + continue; } envVars[activeNdx].active = true; } @@ -560,8 +558,7 @@ __merge_environ(void) if ((equals = strchr(*env, '=')) == NULL) { __env_warnx(CorruptEnvValueMsg, *env, strlen(*env)); - errno = EFAULT; - return (-1); + continue; } if (__setenv(*env, equals - *env, equals + 1, 1) == -1) -- cgit v1.1 From 07b9b1d87c9c827c726ff5d99e9faa57bca3a7ab Mon Sep 17 00:00:00 2001 From: scf Date: Sun, 6 Dec 2009 23:51:27 +0000 Subject: Update the getenv(3) man page to reflect the recent change to the behavior of setenv(), putenv() and unsetenv() when dealing with corrupt entries in environ. They now output a warning and complete their task without error. MFC after: 1 week --- lib/libc/stdlib/getenv.3 | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdlib/getenv.3 b/lib/libc/stdlib/getenv.3 index 33d9c36..fd7d856 100644 --- a/lib/libc/stdlib/getenv.3 +++ b/lib/libc/stdlib/getenv.3 @@ -107,6 +107,15 @@ function deletes all instances of the variable name pointed to by .Fa name from the list. +.Pp +If corruption (e.g., a name without a value) is detected while making a copy of +environ for internal usage, then +.Fn setenv , +.Fn unsetenv +and +.Fn putenv +will output a warning to stderr about the issue, drop the corrupt entry and +complete the task without error. .Sh RETURN VALUES The .Fn getenv @@ -159,15 +168,6 @@ The function or .Fn putenv failed because they were unable to allocate memory for the environment. -.It Bq Er EFAULT -The functions -.Fn setenv , -.Fn unsetenv -or -.Fn putenv -failed to make a valid copy of the environment due to the environment being -corrupt (i.e., a name without a value). A warning will be output to stderr with -information about the issue. .El .Sh SEE ALSO .Xr csh 1 , -- cgit v1.1 From c1fd4ec15e0c7afdbf59a0bfb1253de4977ed9b5 Mon Sep 17 00:00:00 2001 From: scf Date: Mon, 7 Dec 2009 00:22:10 +0000 Subject: Revert behavior change to setenv(), unsetenv() and putenv() until a more thorough security review has been completed. --- lib/libc/stdlib/getenv.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdlib/getenv.c b/lib/libc/stdlib/getenv.c index 4617f45..b7826d7 100644 --- a/lib/libc/stdlib/getenv.c +++ b/lib/libc/stdlib/getenv.c @@ -361,7 +361,8 @@ __build_env(void) } else { __env_warnx(CorruptEnvValueMsg, envVars[envNdx].name, strlen(envVars[envNdx].name)); - continue; + errno = EFAULT; + goto Failure; } /* @@ -376,7 +377,8 @@ __build_env(void) false) == NULL) { __env_warnx(CorruptEnvFindMsg, envVars[envNdx].name, nameLen); - continue; + errno = EFAULT; + goto Failure; } envVars[activeNdx].active = true; } @@ -558,7 +560,8 @@ __merge_environ(void) if ((equals = strchr(*env, '=')) == NULL) { __env_warnx(CorruptEnvValueMsg, *env, strlen(*env)); - continue; + errno = EFAULT; + return (-1); } if (__setenv(*env, equals - *env, equals + 1, 1) == -1) -- cgit v1.1 From 55d035ed41399d1592a676410827fd08879a3898 Mon Sep 17 00:00:00 2001 From: jilles Date: Tue, 8 Dec 2009 20:48:06 +0000 Subject: sem_init(3): document process shared semaphores and their restrictions --- lib/libc/gen/sem_init.3 | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/sem_init.3 b/lib/libc/gen/sem_init.3 index d765a57..202612a 100644 --- a/lib/libc/gen/sem_init.3 +++ b/lib/libc/gen/sem_init.3 @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 15, 2000 +.Dd December 8, 2009 .Dt SEM_INIT 3 .Os .Sh NAME @@ -48,8 +48,7 @@ to have the value .Fa value . A non-zero value for .Fa pshared -specifies a shared semaphore that can be used by multiple processes, which this -implementation is not capable of. +specifies a shared semaphore that can be used by multiple processes. .Pp Following a successful call to .Fn sem_init , @@ -78,8 +77,6 @@ argument exceeds .Dv SEM_VALUE_MAX . .It Bq Er ENOSPC Memory allocation error. -.It Bq Er EPERM -Unable to initialize a shared semaphore. .El .Sh SEE ALSO .Xr sem_destroy 3 , @@ -93,16 +90,10 @@ The .Fn sem_init function conforms to .St -p1003.1-96 . -.Pp -This implementation does not support shared semaphores, and reports this fact -by setting -.Va errno -to -.Er EPERM . -This is perhaps a stretch of the intention of -.Tn POSIX , -but is -compliant, with the caveat that -.Fn sem_init -always reports a permissions error when an attempt to create a shared semaphore -is made. +.Sh BUGS +A sem_t is a pointer to a separately allocated structure, +therefore process shared semaphores only work between related processes +and do not perform very well +(each operation is a system call, +while single-process semaphores only do a system call +if they need to block or wake up a thread). -- cgit v1.1 From 06dc67d8bbf34ff22e9f8e02f44160f1100db219 Mon Sep 17 00:00:00 2001 From: jasone Date: Thu, 10 Dec 2009 00:16:11 +0000 Subject: Fix the posix_memalign() changes in r196861 to actually return a NULL pointer as intended. PR: standards/138307 --- lib/libc/stdlib/malloc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/libc') diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c index 8527496..53119fd 100644 --- a/lib/libc/stdlib/malloc.c +++ b/lib/libc/stdlib/malloc.c @@ -5340,6 +5340,7 @@ posix_memalign(void **memptr, size_t alignment, size_t size) size = 1; else { result = NULL; + *memptr = NULL; ret = 0; goto RETURN; } -- cgit v1.1 From 6e354b089d9a67edb1364fc96a1a26d764f713ff Mon Sep 17 00:00:00 2001 From: jasone Date: Thu, 10 Dec 2009 02:51:40 +0000 Subject: Simplify arena_run_reg_dalloc(), and remove a bug that was due to incorrect initialization of ssize_invs. --- lib/libc/stdlib/malloc.c | 117 ++++++++++++----------------------------------- 1 file changed, 28 insertions(+), 89 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c index 53119fd..e1b3f33 100644 --- a/lib/libc/stdlib/malloc.c +++ b/lib/libc/stdlib/malloc.c @@ -2419,7 +2419,7 @@ arena_run_reg_alloc(arena_run_t *run, arena_bin_t *bin) static inline void arena_run_reg_dalloc(arena_run_t *run, arena_bin_t *bin, void *ptr, size_t size) { - unsigned diff, regind, elm, bit; + unsigned shift, diff, regind, elm, bit; assert(run->magic == ARENA_RUN_MAGIC); @@ -2428,31 +2428,16 @@ arena_run_reg_dalloc(arena_run_t *run, arena_bin_t *bin, void *ptr, size_t size) * actual division here can reduce allocator throughput by over 20%! */ diff = (unsigned)((uintptr_t)ptr - (uintptr_t)run - bin->reg0_offset); - if ((size & (size - 1)) == 0) { - /* - * log2_table allows fast division of a power of two in the - * [1..128] range. - * - * (x / divisor) becomes (x >> log2_table[divisor - 1]). - */ - static const unsigned char log2_table[] = { - 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7 - }; - if (size <= 128) - regind = (diff >> log2_table[size - 1]); - else if (size <= 32768) - regind = diff >> (8 + log2_table[(size >> 8) - 1]); - else - regind = diff / size; - } else if (size < qspace_max) { + /* Rescale (factor powers of 2 out of the numerator and denominator). */ + shift = ffs(size) - 1; + diff >>= shift; + size >>= shift; + + if (size == 1) { + /* The divisor was a power of 2. */ + regind = diff; + } else { /* * To divide by a number D that is not a power of two we * multiply by (2^21 / D) and then right shift by 21 positions. @@ -2461,78 +2446,32 @@ arena_run_reg_dalloc(arena_run_t *run, arena_bin_t *bin, void *ptr, size_t size) * * becomes * - * (X * qsize_invs[(D >> QUANTUM_2POW) - 3]) - * >> SIZE_INV_SHIFT + * (X * size_invs[D - 3]) >> SIZE_INV_SHIFT * * We can omit the first three elements, because we never - * divide by 0, and QUANTUM and 2*QUANTUM are both powers of - * two, which are handled above. + * divide by 0, and 1 and 2 are both powers of two, which are + * handled above. */ #define SIZE_INV_SHIFT 21 -#define QSIZE_INV(s) (((1U << SIZE_INV_SHIFT) / (s << QUANTUM_2POW)) + 1) - static const unsigned qsize_invs[] = { - QSIZE_INV(3), - QSIZE_INV(4), QSIZE_INV(5), QSIZE_INV(6), QSIZE_INV(7) -#if (QUANTUM_2POW < 4) - , - QSIZE_INV(8), QSIZE_INV(9), QSIZE_INV(10), QSIZE_INV(11), - QSIZE_INV(12),QSIZE_INV(13), QSIZE_INV(14), QSIZE_INV(15) -#endif +#define SIZE_INV(s) (((1U << SIZE_INV_SHIFT) / (s)) + 1) + static const unsigned size_invs[] = { + SIZE_INV(3), + SIZE_INV(4), SIZE_INV(5), SIZE_INV(6), SIZE_INV(7), + SIZE_INV(8), SIZE_INV(9), SIZE_INV(10), SIZE_INV(11), + SIZE_INV(12), SIZE_INV(13), SIZE_INV(14), SIZE_INV(15), + SIZE_INV(16), SIZE_INV(17), SIZE_INV(18), SIZE_INV(19), + SIZE_INV(20), SIZE_INV(21), SIZE_INV(22), SIZE_INV(23), + SIZE_INV(24), SIZE_INV(25), SIZE_INV(26), SIZE_INV(27), + SIZE_INV(28), SIZE_INV(29), SIZE_INV(30), SIZE_INV(31) }; - assert(QUANTUM * (((sizeof(qsize_invs)) / sizeof(unsigned)) + 3) - >= (1U << QSPACE_MAX_2POW_DEFAULT)); - if (size <= (((sizeof(qsize_invs) / sizeof(unsigned)) + 2) << - QUANTUM_2POW)) { - regind = qsize_invs[(size >> QUANTUM_2POW) - 3] * diff; - regind >>= SIZE_INV_SHIFT; - } else - regind = diff / size; -#undef QSIZE_INV - } else if (size < cspace_max) { -#define CSIZE_INV(s) (((1U << SIZE_INV_SHIFT) / (s << CACHELINE_2POW)) + 1) - static const unsigned csize_invs[] = { - CSIZE_INV(3), - CSIZE_INV(4), CSIZE_INV(5), CSIZE_INV(6), CSIZE_INV(7) - }; - assert(CACHELINE * (((sizeof(csize_invs)) / sizeof(unsigned)) + - 3) >= (1U << CSPACE_MAX_2POW_DEFAULT)); - - if (size <= (((sizeof(csize_invs) / sizeof(unsigned)) + 2) << - CACHELINE_2POW)) { - regind = csize_invs[(size >> CACHELINE_2POW) - 3] * - diff; - regind >>= SIZE_INV_SHIFT; - } else - regind = diff / size; -#undef CSIZE_INV - } else { -#define SSIZE_INV(s) (((1U << SIZE_INV_SHIFT) / (s << SUBPAGE_2POW)) + 1) - static const unsigned ssize_invs[] = { - SSIZE_INV(3), - SSIZE_INV(4), SSIZE_INV(5), SSIZE_INV(6), SSIZE_INV(7), - SSIZE_INV(8), SSIZE_INV(9), SSIZE_INV(10), SSIZE_INV(11), - SSIZE_INV(12), SSIZE_INV(13), SSIZE_INV(14), SSIZE_INV(15) -#if (PAGE_SHIFT == 13) - , - SSIZE_INV(16), SSIZE_INV(17), SSIZE_INV(18), SSIZE_INV(19), - SSIZE_INV(20), SSIZE_INV(21), SSIZE_INV(22), SSIZE_INV(23), - SSIZE_INV(24), SSIZE_INV(25), SSIZE_INV(26), SSIZE_INV(27), - SSIZE_INV(28), SSIZE_INV(29), SSIZE_INV(29), SSIZE_INV(30) -#endif - }; - assert(SUBPAGE * (((sizeof(ssize_invs)) / sizeof(unsigned)) + 3) - >= PAGE_SIZE); - - if (size < (((sizeof(ssize_invs) / sizeof(unsigned)) + 2) << - SUBPAGE_2POW)) { - regind = ssize_invs[(size >> SUBPAGE_2POW) - 3] * diff; - regind >>= SIZE_INV_SHIFT; - } else + if (size <= ((sizeof(size_invs) / sizeof(unsigned)) + 2)) + regind = (diff * size_invs[size - 3]) >> SIZE_INV_SHIFT; + else regind = diff / size; -#undef SSIZE_INV - } +#undef SIZE_INV #undef SIZE_INV_SHIFT + } assert(diff == regind * size); assert(regind < bin->nregs); -- cgit v1.1 From 2a4bb5bd52199df9430fbf220f37107ffda1b221 Mon Sep 17 00:00:00 2001 From: jilles Date: Tue, 15 Dec 2009 21:02:29 +0000 Subject: cpuset(2): fix a typo and a markup error in the man page MFC after: 1 week --- lib/libc/sys/cpuset.2 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/sys/cpuset.2 b/lib/libc/sys/cpuset.2 index c07f8d9..fb9a770 100644 --- a/lib/libc/sys/cpuset.2 +++ b/lib/libc/sys/cpuset.2 @@ -96,7 +96,7 @@ The .Fa which argument may have the following values: .Bl -column CPU_WHICH_CPUSET -offset indent -.It Dv CPU_WHICH_TID Ta "id is lpwid_t (thread id)" +.It Dv CPU_WHICH_TID Ta "id is lwpid_t (thread id)" .It Dv CPU_WHICH_PID Ta "id is pid_t (process id)" .It Dv CPU_WHICH_CPUSET Ta "id is a cpusetid_t (cpuset id)" .It Dv CPU_WHICH_IRQ Ta "id is an irq number" @@ -209,7 +209,7 @@ The calling process did not have the credentials required to complete the operation. .It Bq Er ENFILE There was no free -.Fn cpusetid_t +.Ft cpusetid_t for allocation. .El .Sh SEE ALSO -- cgit v1.1 From fbf6bc755d9348f8fdac7ce114675df2c9424cee Mon Sep 17 00:00:00 2001 From: matteo Date: Wed, 16 Dec 2009 04:19:23 +0000 Subject: --- lib/libc/stdio/getline.3 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/stdio/getline.3 b/lib/libc/stdio/getline.3 index 0465f93..a5b39da 100644 --- a/lib/libc/stdio/getline.3 +++ b/lib/libc/stdio/getline.3 @@ -78,7 +78,8 @@ and .Fn getline functions return the number of characters written, excluding the terminating -.Dv NUL . +.Dv NUL +character. The value \-1 is returned if an error occurs, or if end-of-file is reached. .Sh EXAMPLES The following code fragment reads lines from a file and -- cgit v1.1 From 257e93c9a0eba2f74e73a06f18fea91d461f6e15 Mon Sep 17 00:00:00 2001 From: jhb Date: Mon, 21 Dec 2009 19:43:23 +0000 Subject: Use _once() to initialize the pthread key for thread-local storage to hold the results of localtime() instead of using a pthread mutex directly. MFC after: 1 week --- lib/libc/stdtime/localtime.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdtime/localtime.c b/lib/libc/stdtime/localtime.c index d391e3e..640078d 100644 --- a/lib/libc/stdtime/localtime.c +++ b/lib/libc/stdtime/localtime.c @@ -237,6 +237,9 @@ static char lcl_TZname[TZ_STRLEN_MAX + 1]; static int lcl_is_set; static pthread_once_t gmt_once = PTHREAD_ONCE_INIT; static pthread_rwlock_t lcl_rwlock = PTHREAD_RWLOCK_INITIALIZER; +static pthread_once_t localtime_once = PTHREAD_ONCE_INIT; +static pthread_key_t localtime_key; +static int localtime_key_error; char * tzname[2] = { wildabbr, @@ -1406,27 +1409,24 @@ struct tm * const tmp; return result; } +static void +localtime_key_init(void) +{ + + localtime_key_error = _pthread_key_create(&localtime_key, free); +} + struct tm * localtime(timep) const time_t * const timep; { - static pthread_mutex_t localtime_mutex = PTHREAD_MUTEX_INITIALIZER; - static pthread_key_t localtime_key = -1; struct tm *p_tm; - int r; if (__isthreaded != 0) { - if (localtime_key < 0) { - _pthread_mutex_lock(&localtime_mutex); - if (localtime_key < 0) { - if ((r = _pthread_key_create(&localtime_key, - free)) != 0) { - _pthread_mutex_unlock(&localtime_mutex); - errno = r; - return(NULL); - } - } - _pthread_mutex_unlock(&localtime_mutex); + _once(&localtime_once, localtime_key_init); + if (localtime_key_error != 0) { + errno = localtime_key_error; + return(NULL); } p_tm = _pthread_getspecific(localtime_key); if (p_tm == NULL) { -- cgit v1.1 From 71977347f2ff3650a930308e5154ffc9096f72c8 Mon Sep 17 00:00:00 2001 From: delphij Date: Mon, 21 Dec 2009 19:55:05 +0000 Subject: K&R -> ANSI prototype. MFC after: 1 month --- lib/libc/stdio/vsscanf.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdio/vsscanf.c b/lib/libc/stdio/vsscanf.c index e5e9691..22b5d2b 100644 --- a/lib/libc/stdio/vsscanf.c +++ b/lib/libc/stdio/vsscanf.c @@ -45,20 +45,15 @@ eofread(void *, char *, int); /* ARGSUSED */ static int -eofread(cookie, buf, len) - void *cookie; - char *buf; - int len; +eofread(void *cookie, char *buf, int len) { return (0); } int -vsscanf(str, fmt, ap) - const char * __restrict str; - const char * __restrict fmt; - __va_list ap; +vsscanf(const char * __restrict str, const char * __restrict fmt, + __va_list ap) { FILE f; -- cgit v1.1 From 45f47d9a5ff5b0b541b5a0bbbea010553ff5e743 Mon Sep 17 00:00:00 2001 From: delphij Date: Mon, 21 Dec 2009 19:56:03 +0000 Subject: Use vsscanf instead of rolling our own. PR: bin/140530 Submitted by: Jeremy Huddleston MFC after: 1 month --- lib/libc/stdio/sscanf.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdio/sscanf.c b/lib/libc/stdio/sscanf.c index 3c792e0..c793b86 100644 --- a/lib/libc/stdio/sscanf.c +++ b/lib/libc/stdio/sscanf.c @@ -41,37 +41,14 @@ __FBSDID("$FreeBSD$"); #include #include "local.h" -static int eofread(void *, char *, int); - -/* ARGSUSED */ -static int -eofread(cookie, buf, len) - void *cookie; - char *buf; - int len; -{ - - return (0); -} - int sscanf(const char * __restrict str, char const * __restrict fmt, ...) { int ret; va_list ap; - FILE f; - f._file = -1; - f._flags = __SRD; - f._bf._base = f._p = (unsigned char *)str; - f._bf._size = f._r = strlen(str); - f._read = eofread; - f._ub._base = NULL; - f._lb._base = NULL; - f._orientation = 0; - memset(&f._mbstate, 0, sizeof(mbstate_t)); va_start(ap, fmt); - ret = __svfscanf(&f, fmt, ap); + ret = vsscanf(str, fmt, ap); va_end(ap); return (ret); } -- cgit v1.1 From e3103880d83f1af0b22d4844a1cb8df5f1bed047 Mon Sep 17 00:00:00 2001 From: delphij Date: Mon, 21 Dec 2009 19:59:38 +0000 Subject: Use vsprintf instead of rolling our own. PR: bin/140496 Submitted by: Jeremy Huddleston MFC after: 1 month --- lib/libc/stdio/sprintf.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdio/sprintf.c b/lib/libc/stdio/sprintf.c index aaaae55..b55bd6c 100644 --- a/lib/libc/stdio/sprintf.c +++ b/lib/libc/stdio/sprintf.c @@ -46,17 +46,9 @@ sprintf(char * __restrict str, char const * __restrict fmt, ...) { int ret; va_list ap; - FILE f; - f._file = -1; - f._flags = __SWR | __SSTR; - f._bf._base = f._p = (unsigned char *)str; - f._bf._size = f._w = INT_MAX; - f._orientation = 0; - memset(&f._mbstate, 0, sizeof(mbstate_t)); va_start(ap, fmt); - ret = __vfprintf(&f, fmt, ap); + ret = vsprintf(str, fmt, ap); va_end(ap); - *f._p = 0; return (ret); } -- cgit v1.1 From eddea47c4f1c1ee6d3ef38fb820998f385c02d13 Mon Sep 17 00:00:00 2001 From: edwin Date: Tue, 22 Dec 2009 11:17:10 +0000 Subject: MFV of tzdata2009t, r200831 zic: - Fix URL / reference to Calendrical Calculations: Third Edition libc/stdtime: - Fix typo in tzfile.5 (no changes in our part) MFC after: 1 week --- lib/libc/stdtime/tzfile.5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/stdtime/tzfile.5 b/lib/libc/stdtime/tzfile.5 index 15625d2..1606b5a 100644 --- a/lib/libc/stdtime/tzfile.5 +++ b/lib/libc/stdtime/tzfile.5 @@ -147,6 +147,6 @@ such instants). .Xr ctime 3 , .Xr time2posix 3 , .Xr zic 8 -.\" @(#)tzfile.5 8.2 +.\" @(#)tzfile.5 8.3 .\" This file is in the public domain, so clarified as of .\" 1996-06-05 by Arthur David Olson. -- cgit v1.1 From de21e8d4af0e2f652c8c84fd1155a2170de348c1 Mon Sep 17 00:00:00 2001 From: markus Date: Fri, 25 Dec 2009 18:05:06 +0000 Subject: Use a local copy of entry_d for finding matches. Otherwise, if entry_d pointed to an entry of 'acl', all ACL entries starting with entry_d would be deleted. Reviewed by: trasz Approved by: emax (mentor) MFC after: 3 days --- lib/libc/posix1e/acl_delete_entry.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/posix1e/acl_delete_entry.c b/lib/libc/posix1e/acl_delete_entry.c index 7dd60b8..09b4507 100644 --- a/lib/libc/posix1e/acl_delete_entry.c +++ b/lib/libc/posix1e/acl_delete_entry.c @@ -75,6 +75,7 @@ int acl_delete_entry(acl_t acl, acl_entry_t entry_d) { struct acl *acl_int; + struct acl_entry entry_int; int i, j, found = 0; if (acl == NULL || entry_d == NULL) { @@ -94,8 +95,12 @@ acl_delete_entry(acl_t acl, acl_entry_t entry_d) errno = EINVAL; return (-1); } + + /* Use a local copy to prevent deletion of more than this entry */ + entry_int = *entry_d; + for (i = 0; i < acl->ats_acl.acl_cnt;) { - if (_entry_matches(&(acl->ats_acl.acl_entry[i]), entry_d)) { + if (_entry_matches(&(acl->ats_acl.acl_entry[i]), &entry_int)) { /* ...shift the remaining entries... */ for (j = i; j < acl->ats_acl.acl_cnt - 1; ++j) acl->ats_acl.acl_entry[j] = -- cgit v1.1 From bfd388c026e6aeb5427df50347b59d62feb3072e Mon Sep 17 00:00:00 2001 From: antoine Date: Mon, 28 Dec 2009 22:56:30 +0000 Subject: (S)LIST_HEAD_INITIALIZER takes a (S)LIST_HEAD as an argument. Fix some wrong usages. Note: this does not affect generated binaries as this argument is not used. PR: 137213 Submitted by: Eygene Ryabinkin (initial version) MFC after: 1 month --- lib/libc/gen/sem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/sem.c b/lib/libc/gen/sem.c index 439f0fe..cd31d31 100644 --- a/lib/libc/gen/sem.c +++ b/lib/libc/gen/sem.c @@ -73,7 +73,7 @@ static sem_t sem_alloc(unsigned int value, semid_t semid, int system_sem); static void sem_free(sem_t sem); -static LIST_HEAD(, sem) named_sems = LIST_HEAD_INITIALIZER(&named_sems); +static LIST_HEAD(, sem) named_sems = LIST_HEAD_INITIALIZER(named_sems); static pthread_mutex_t named_sems_mtx = PTHREAD_MUTEX_INITIALIZER; __weak_reference(__sem_init, sem_init); -- cgit v1.1 From aa28c3213861962a9da4732d118054f285c25df9 Mon Sep 17 00:00:00 2001 From: kib Date: Tue, 29 Dec 2009 12:47:47 +0000 Subject: Use clock_gettime(CLOCK_SECOND) instead of gettimeofday(2) for implementation of time(3). CLOCK_SECOND is much faster. No objections from: phk Submitted by: Valentin Nechayev MFC after: 1 week --- lib/libc/gen/time.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/time.c b/lib/libc/gen/time.c index 840f9b6..214dfce 100644 --- a/lib/libc/gen/time.c +++ b/lib/libc/gen/time.c @@ -37,13 +37,12 @@ __FBSDID("$FreeBSD$"); #include time_t -time(t) - time_t *t; +time(time_t *t) { - struct timeval tt; + struct timespec tt; time_t retval; - if (gettimeofday(&tt, (struct timezone *)0) < 0) + if (clock_gettime(CLOCK_SECOND, &tt) < 0) retval = -1; else retval = tt.tv_sec; -- cgit v1.1 From fb28939ce7beb7a398a69e31346008d37d6dfbb0 Mon Sep 17 00:00:00 2001 From: kib Date: Tue, 29 Dec 2009 14:29:08 +0000 Subject: Document CLOCK_SECOND, add cross-reference from time(3) to clock_gettime(2). Based on submission by: pluknet gmail com MFC after: 3 days --- lib/libc/gen/time.3 | 1 + lib/libc/sys/clock_gettime.2 | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/time.3 b/lib/libc/gen/time.3 index 2770e49..d022e06 100644 --- a/lib/libc/gen/time.3 +++ b/lib/libc/gen/time.3 @@ -66,6 +66,7 @@ The function may fail for any of the reasons described in .Xr gettimeofday 2 . .Sh SEE ALSO +.Xr clock_gettime 2 , .Xr gettimeofday 2 , .Xr ctime 3 .Sh STANDARDS diff --git a/lib/libc/sys/clock_gettime.2 b/lib/libc/sys/clock_gettime.2 index 242af1c..485cd25 100644 --- a/lib/libc/sys/clock_gettime.2 +++ b/lib/libc/sys/clock_gettime.2 @@ -29,7 +29,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 4, 2006 +.Dd December 29, 2009 .Dt CLOCK_GETTIME 2 .Os .Sh NAME @@ -70,10 +70,13 @@ which starts at zero when the kernel boots and increments monotonically in SI seconds while the machine is running, .Dv CLOCK_VIRTUAL for time that increments only when -the CPU is running in user mode on behalf of the calling process, or +the CPU is running in user mode on behalf of the calling process, .Dv CLOCK_PROF for time that increments when the CPU is running in user or -kernel mode. +kernel mode, or +.Dv CLOCK_SECOND +which returns the current second without performing a full time counter +query, using in-kernel cached value of current second. .Pp The structure pointed to by .Fa tp -- cgit v1.1 From 04f9b92f28cff9016ff2989291b8a6edebbffa2f Mon Sep 17 00:00:00 2001 From: kib Date: Tue, 29 Dec 2009 15:58:10 +0000 Subject: Document _FAST and _PRECISE clocks. Submitted by: Valentin Nechayev MFC after: 3 days --- lib/libc/sys/clock_gettime.2 | 50 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 10 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/sys/clock_gettime.2 b/lib/libc/sys/clock_gettime.2 index 485cd25..a2fa624 100644 --- a/lib/libc/sys/clock_gettime.2 +++ b/lib/libc/sys/clock_gettime.2 @@ -59,25 +59,44 @@ used by a clock which is specified by The .Fa clock_id argument -can be one of five values: -.Dv CLOCK_REALTIME +can be one of the following values: +.Dv CLOCK_REALTIME , +.Dv CLOCK_REALTIME_PRECISE , +.Dv CLOCK_REALTIME_FAST for time that increments as -a wall clock should, -.Dv CLOCK_MONOTONIC -which increments in SI seconds, -.Dv CLOCK_UPTIME +a wall clock should; +.Dv CLOCK_MONOTONIC , +.Dv CLOCK_MONOTONIC_PRECISE , +.Dv CLOCK_MONOTONIC_FAST +which increments in SI seconds; +.Dv CLOCK_UPTIME , +.Dv CLOCK_UPTIME_PRECISE , +.Dv CLOCK_UPTIME_FAST which starts at zero when the kernel boots and increments -monotonically in SI seconds while the machine is running, +monotonically in SI seconds while the machine is running; .Dv CLOCK_VIRTUAL for time that increments only when -the CPU is running in user mode on behalf of the calling process, +the CPU is running in user mode on behalf of the calling process; .Dv CLOCK_PROF for time that increments when the CPU is running in user or -kernel mode, or +kernel mode; or .Dv CLOCK_SECOND which returns the current second without performing a full time counter query, using in-kernel cached value of current second. .Pp +The clock IDs +.Fa CLOCK_REALTIME_FAST , +.Fa CLOCK_MONOTONIC_FAST , +.Fa CLOCK_UPTIME_FAST +are analogs of corresponding IDs without _FAST suffix but do not perform +a full time counter query, so their accuracy is one timer tick. +Similarly, +.Fa CLOCK_REALTIME_PRECISE , +.Fa CLOCK_MONOTONIC_PRECISE , +.Fa CLOCK_UPTIME_PRECISE +are used to get the most exact value as possible, at the expense of +execution time. +.Pp The structure pointed to by .Fa tp is defined in @@ -91,7 +110,8 @@ struct timespec { }; .Ed .Pp -Only the super-user may set the time of day. +Only the super-user may set the time of day, using only +.Fa CLOCK_REALTIME . If the system securelevel is greater than 1 (see .Xr init 8 ) , the time may only be advanced. @@ -137,3 +157,13 @@ and .Fn clock_getres system calls conform to .St -p1003.1b-93 . +The clock IDs +.Fa CLOCK_REALTIME_FAST , +.Fa CLOCK_REALTIME_PRECISE , +.Fa CLOCK_MONOTONIC_FAST , +.Fa CLOCK_MONOTONIC_PRECISE , +.Fa CLOCK_UPTIME , +.Fa CLOCK_UPTIME_FAST , +.Fa CLOCK_UPTIME_PRECISE , +.Fa CLOCK_SECOND +are FreeBSD extensions to the POSIX interface. -- cgit v1.1 From ab18b95f4ca8b361598ace60f0aa89148c1ce9bc Mon Sep 17 00:00:00 2001 From: jhb Date: Wed, 30 Dec 2009 19:06:16 +0000 Subject: Use _once() to initialize the pthread key for thread-local storage to hold the results of gmtime() instead of using a pthread mutex directly. MFC after: 1 week --- lib/libc/stdtime/localtime.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdtime/localtime.c b/lib/libc/stdtime/localtime.c index 640078d..ad26f7e 100644 --- a/lib/libc/stdtime/localtime.c +++ b/lib/libc/stdtime/localtime.c @@ -237,6 +237,9 @@ static char lcl_TZname[TZ_STRLEN_MAX + 1]; static int lcl_is_set; static pthread_once_t gmt_once = PTHREAD_ONCE_INIT; static pthread_rwlock_t lcl_rwlock = PTHREAD_RWLOCK_INITIALIZER; +static pthread_once_t gmtime_once = PTHREAD_ONCE_INIT; +static pthread_key_t gmtime_key; +static int gmtime_key_error; static pthread_once_t localtime_once = PTHREAD_ONCE_INIT; static pthread_key_t localtime_key; static int localtime_key_error; @@ -1510,27 +1513,24 @@ struct tm * const tmp; return result; } +static void +gmtime_key_init(void) +{ + + gmtime_key_error = _pthread_key_create(&gmtime_key, free); +} + struct tm * gmtime(timep) const time_t * const timep; { - static pthread_mutex_t gmtime_mutex = PTHREAD_MUTEX_INITIALIZER; - static pthread_key_t gmtime_key = -1; struct tm *p_tm; - int r; if (__isthreaded != 0) { - if (gmtime_key < 0) { - _pthread_mutex_lock(&gmtime_mutex); - if (gmtime_key < 0) { - if ((r = _pthread_key_create(&gmtime_key, - free)) != 0) { - _pthread_mutex_unlock(&gmtime_mutex); - errno = r; - return(NULL); - } - } - _pthread_mutex_unlock(&gmtime_mutex); + _once(&gmtime_once, gmtime_key_init); + if (gmtime_key_error != 0) { + errno = gmtime_key_error; + return(NULL); } /* * Changed to follow POSIX.1 threads standard, which -- cgit v1.1 From a5cc24440bfbf4dc6eeb27b3770d09132b85bd31 Mon Sep 17 00:00:00 2001 From: brooks Date: Thu, 31 Dec 2009 20:29:58 +0000 Subject: The devices that supported EVFILT_NETDEV kqueue filters were removed in r195175. Remove all definitions, documentation, and usage. fifo_misc.c: Remove all kqueue tests as fifo_io.c performs all those that would have remained. Reviewed by: rwatson MFC after: 3 weeks X-MFC note: don't change vlan_link_state() function signature --- lib/libc/sys/kqueue.2 | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/sys/kqueue.2 b/lib/libc/sys/kqueue.2 index e899a1b..326632d 100644 --- a/lib/libc/sys/kqueue.2 +++ b/lib/libc/sys/kqueue.2 @@ -438,19 +438,6 @@ There is a system wide limit on the number of timers which is controlled by the .Va kern.kq_calloutmax sysctl. -.It Dv EVFILT_NETDEV -Takes a descriptor to a network interface as the identifier, and the events to watch for in -.Va fflags . -It returns, when one or more of the requested events occur on the descriptor. -The events to monitor are: -.Bl -tag -width XXNOTE_LINKDOWN -.It Dv NOTE_LINKUP -The link is up. -.It Dv NOTE_LINKDOWN -The link is down. -.It Dv NOTE_LINKINV -The link state is invalid. -.El .Pp On return, .Va fflags @@ -595,13 +582,6 @@ system and this manual page were written by .An Jonathan Lemon Aq jlemon@FreeBSD.org . .Sh BUGS The -.Dv EVFILT_NETDEV -filter is currently only implemented for devices that use the -.Xr miibus 4 -driver for LINKUP and LINKDOWN operations. -Therefore, it will not work with many non-ethernet devices. -.Pp -The .Fa timeout value is limited to 24 hours; longer timeouts will be silently reinterpreted as 24 hours. -- cgit v1.1 From a922794e92f1d71cc8cce3b0a28fb257186744f8 Mon Sep 17 00:00:00 2001 From: ed Date: Sat, 2 Jan 2010 20:27:14 +0000 Subject: Don't forget to clean up the file copied from the kernel sources. MFC after: 1 week --- lib/libc/posix1e/Makefile.inc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/posix1e/Makefile.inc b/lib/libc/posix1e/Makefile.inc index c9e78bd..30e3986 100644 --- a/lib/libc/posix1e/Makefile.inc +++ b/lib/libc/posix1e/Makefile.inc @@ -119,3 +119,5 @@ MLINKS+=acl_create_entry.3 acl_create_entry_np.3\ mac_set.3 mac_set_proc.3 \ mac_text.3 mac_from_text.3 \ mac_text.3 mac_to_text.3 + +CLEANFILES+= subr_acl_nfs4.c -- cgit v1.1 From d061de008ac2d14466eefecb47b69b59e5e79408 Mon Sep 17 00:00:00 2001 From: kib Date: Mon, 4 Jan 2010 15:40:17 +0000 Subject: Modernize scandir(3) and alphasort(3) interfaces according to the IEEE Std 1003.1-2008. Both Linux and Solaris conforms to the new definitions, so we better follow too (older glibc used old BSDish alphasort prototype and corresponding type of the comparision function for scandir). While there, change the definitions of the functions to ANSI C and fix several style issues nearby. Remove requirement for "sys/types.h" include for functions from manpage. POSIX also requires that alphasort(3) sorts as if strcoll(3) was used, but leave the strcmp(3) call in the function for now. Adapt in-tree callers of scandir(3) to new declaration. The fact that select_sections() from catman(1) could modify supplied struct dirent is a bug. PR: standards/142255 MFC after: 2 weeks --- lib/libc/gen/opendir.c | 3 ++- lib/libc/gen/scandir.3 | 7 +++---- lib/libc/gen/scandir.c | 23 ++++++++++------------- 3 files changed, 15 insertions(+), 18 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/opendir.c b/lib/libc/gen/opendir.c index 9625ec6..631c4d6 100644 --- a/lib/libc/gen/opendir.c +++ b/lib/libc/gen/opendir.c @@ -240,7 +240,8 @@ __opendir_common(int fd, const char *name, int flags) /* * This sort must be stable. */ - mergesort(dpv, n, sizeof(*dpv), alphasort); + mergesort(dpv, n, sizeof(*dpv), (int (*)(const + void *, const void *))alphasort); dpv[n] = NULL; xp = NULL; diff --git a/lib/libc/gen/scandir.3 b/lib/libc/gen/scandir.3 index 42ccac2..5e177b9 100644 --- a/lib/libc/gen/scandir.3 +++ b/lib/libc/gen/scandir.3 @@ -28,7 +28,7 @@ .\" @(#)scandir.3 8.1 (Berkeley) 6/4/93 .\" $FreeBSD$ .\" -.Dd June 4, 1993 +.Dd January 3, 2010 .Dt SCANDIR 3 .Os .Sh NAME @@ -38,12 +38,11 @@ .Sh LIBRARY .Lb libc .Sh SYNOPSIS -.In sys/types.h .In dirent.h .Ft int -.Fn scandir "const char *dirname" "struct dirent ***namelist" "int \\*(lp*select\\*(rp\\*(lpstruct dirent *\\*(rp" "int \\*(lp*compar\\*(rp\\*(lpconst void *, const void *\\*(rp" +.Fn scandir "const char *dirname" "struct dirent ***namelist" "int \\*(lp*select\\*(rp\\*(lpconst struct dirent *\\*(rp" "int \\*(lp*compar\\*(rp\\*(lpconst struct dirent **, const struct dirent **\\*(rp" .Ft int -.Fn alphasort "const void *d1" "const void *d2" +.Fn alphasort "const struct dirent **d1" "const struct dirent **d2" .Sh DESCRIPTION The .Fn scandir diff --git a/lib/libc/gen/scandir.c b/lib/libc/gen/scandir.c index 1dae85d..47fad1d 100644 --- a/lib/libc/gen/scandir.c +++ b/lib/libc/gen/scandir.c @@ -58,11 +58,9 @@ __FBSDID("$FreeBSD$"); (((dp)->d_namlen + 1 + 3) &~ 3)) int -scandir(dirname, namelist, select, dcomp) - const char *dirname; - struct dirent ***namelist; - int (*select)(struct dirent *); - int (*dcomp)(const void *, const void *); +scandir(const char *dirname, struct dirent ***namelist, + int (*select)(const struct dirent *), int (*dcomp)(const struct dirent **, + const struct dirent **)) { struct dirent *d, *p, **names = NULL; size_t nitems = 0; @@ -111,26 +109,25 @@ scandir(dirname, namelist, select, dcomp) } closedir(dirp); if (nitems && dcomp != NULL) - qsort(names, nitems, sizeof(struct dirent *), dcomp); + qsort(names, nitems, sizeof(struct dirent *), + (int (*)(const void *, const void *))dcomp); *namelist = names; - return(nitems); + return (nitems); fail: while (nitems > 0) free(names[--nitems]); free(names); closedir(dirp); - return -1; + return (-1); } /* * Alphabetic order comparison routine for those who want it. */ int -alphasort(d1, d2) - const void *d1; - const void *d2; +alphasort(const struct dirent **d1, const struct dirent **d2) { - return(strcmp((*(struct dirent **)d1)->d_name, - (*(struct dirent **)d2)->d_name)); + + return (strcmp((*d1)->d_name, (*d2)->d_name)); } -- cgit v1.1 From 87c8a1faf252e6bbed958df4fbcbfae972bf04d9 Mon Sep 17 00:00:00 2001 From: davidxu Date: Tue, 5 Jan 2010 02:37:59 +0000 Subject: Use umtx to implement process sharable semaphore, to make this work, now type sema_t is a structure which can be put in a shared memory area, and multiple processes can operate it concurrently. User can either use mmap(MAP_SHARED) + sem_init(pshared=1) or use sem_open() to initialize a shared semaphore. Named semaphore uses file system and is located in /tmp directory, and its file name is prefixed with 'SEMD', so now it is chroot or jail friendly. In simplist cases, both for named and un-named semaphore, userland code does not have to enter kernel to reduce/increase semaphore's count. The semaphore is designed to be crash-safe, it means even if an application is crashed in the middle of operating semaphore, the semaphore state is still safely recovered by later use, there is no waiter counter maintained by userland code. The main semaphore code is in libc and libthr only has some necessary stubs, this makes it possible that a non-threaded application can use semaphore without linking to thread library. Old semaphore implementation is kept libc to maintain binary compatibility. The kernel ksem API is no longer used in the new implemenation. Discussed on: threads@ --- lib/libc/gen/Makefile.inc | 2 +- lib/libc/gen/Symbol.map | 51 +++-- lib/libc/gen/_pthread_stubs.c | 4 + lib/libc/gen/sem.c | 232 +++++++++++++++----- lib/libc/gen/sem_new.c | 470 ++++++++++++++++++++++++++++++++++++++++ lib/libc/include/libc_private.h | 2 + 6 files changed, 682 insertions(+), 79 deletions(-) create mode 100644 lib/libc/gen/sem_new.c (limited to 'lib/libc') diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index d6b403e..2abfe57 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -25,7 +25,7 @@ SRCS+= __getosreldate.c __xuname.c \ pause.c pmadvise.c popen.c posix_spawn.c \ psignal.c pw_scan.c pwcache.c \ raise.c readdir.c readpassphrase.c rewinddir.c \ - scandir.c seed48.c seekdir.c sem.c semctl.c \ + scandir.c seed48.c seekdir.c sem.c sem_new.c semctl.c \ setdomainname.c sethostname.c setjmperr.c setmode.c \ setproctitle.c setprogname.c siginterrupt.c siglist.c signal.c \ sigsetops.c sleep.c srand48.c statvfs.c stringlist.c strtofflags.c \ diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index a3ea75b..4f75b73 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -236,16 +236,6 @@ FBSD_1.0 { seekdir; user_from_uid; group_from_gid; - sem_init; - sem_destroy; - sem_open; - sem_close; - sem_unlink; - sem_wait; - sem_trywait; - sem_timedwait; - sem_post; - sem_getvalue; setdomainname; sethostname; longjmperror; @@ -363,11 +353,23 @@ FBSD_1.1 { semctl; tcgetsid; tcsetsid; + __pthread_cleanup_pop_imp; + __pthread_cleanup_push_imp; }; FBSD_1.2 { basename_r; getpagesizes; + sem_close; + sem_destroy; + sem_getvalue; + sem_init; + sem_open; + sem_timedwait; + sem_trywait; + sem_post; + sem_wait; + sem_unlink; }; FBSDprivate_1.0 { @@ -456,16 +458,6 @@ FBSDprivate_1.0 { __pw_scan; /* Used by (at least) libutil */ __raise; _raise; - __sem_init; - __sem_destroy; - __sem_open; - __sem_close; - __sem_unlink; - __sem_wait; - __sem_trywait; - __sem_timedwait; - __sem_post; - __sem_getvalue; __sleep; _sleep; _rtld_allocate_tls; @@ -482,4 +474,23 @@ FBSDprivate_1.0 { _wait; __waitpid; _waitpid; + + _libc_sem_destroy; + _libc_sem_init; + _libc_sem_getvalue; + _libc_sem_trywait; + _libc_sem_wait; + _libc_sem_timedwait; + _libc_sem_post; + + _libc_sem_init_compat; + _libc_sem_destroy_compat; + _libc_sem_open_compat; + _libc_sem_close_compat; + _libc_sem_unlink_compat; + _libc_sem_wait_compat; + _libc_sem_trywait_compat; + _libc_sem_timedwait_compat; + _libc_sem_post_compat; + _libc_sem_getvalue_compat; }; diff --git a/lib/libc/gen/_pthread_stubs.c b/lib/libc/gen/_pthread_stubs.c index 147235e..044e299e 100644 --- a/lib/libc/gen/_pthread_stubs.c +++ b/lib/libc/gen/_pthread_stubs.c @@ -119,6 +119,8 @@ pthread_func_entry_t __thr_jtable[PJT_MAX] = { {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_SETSPECIFIC */ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_SIGMASK */ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_TESTCANCEL */ + {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_CLEANUP_POP_IMP */ + {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_CLEANUP_PUSH_IMP */ }; /* @@ -265,6 +267,8 @@ STUB_FUNC2(pthread_kill, PJT_KILL, int, void *, int) STUB_FUNC2(pthread_setcancelstate, PJT_SETCANCELSTATE, int, int, void *) STUB_FUNC2(pthread_setcanceltype, PJT_SETCANCELTYPE, int, int, void *) STUB_FUNC(pthread_testcancel, PJT_TESTCANCEL, void) +STUB_FUNC1(__pthread_cleanup_pop_imp, PJT_CLEANUP_POP_IMP, int, int) +STUB_FUNC2(__pthread_cleanup_push_imp, PJT_CLEANUP_PUSH_IMP, void, void*, void *); static int stub_zero(void) diff --git a/lib/libc/gen/sem.c b/lib/libc/gen/sem.c index cd31d31..4ec7890 100644 --- a/lib/libc/gen/sem.c +++ b/lib/libc/gen/sem.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2010 David Xu . * Copyright (C) 2000 Jason Evans . * All rights reserved. * @@ -59,34 +60,71 @@ #include "namespace.h" #include #include +#include #include +#include +#include +#include #include #include -#include #include #include #include -#include <_semaphore.h> #include "un-namespace.h" #include "libc_private.h" +/* + * Old semaphore definitions. + */ +struct sem { +#define SEM_MAGIC ((u_int32_t) 0x09fa4012) + u_int32_t magic; + pthread_mutex_t lock; + pthread_cond_t gtzero; + u_int32_t count; + u_int32_t nwaiters; +#define SEM_USER (NULL) + semid_t semid; /* semaphore id if kernel (shared) semaphore */ + int syssem; /* 1 if kernel (shared) semaphore */ + LIST_ENTRY(sem) entry; + struct sem **backpointer; +}; + +typedef struct sem* sem_t; + +#define SEM_FAILED ((sem_t *)0) +#define SEM_VALUE_MAX __INT_MAX + +#define SYM_FB10(sym) __CONCAT(sym, _fb10) +#define SYM_FBP10(sym) __CONCAT(sym, _fbp10) +#define WEAK_REF(sym, alias) __weak_reference(sym, alias) +#define SYM_COMPAT(sym, impl, ver) __sym_compat(sym, impl, ver) +#define SYM_DEFAULT(sym, impl, ver) __sym_default(sym, impl, ver) + +#define FB10_COMPAT(func, sym) \ + WEAK_REF(func, SYM_FB10(sym)); \ + SYM_COMPAT(sym, SYM_FB10(sym), FBSD_1.0) + +#define FB10_COMPAT_PRIVATE(func, sym) \ + WEAK_REF(func, SYM_FBP10(sym)); \ + SYM_DEFAULT(sym, SYM_FBP10(sym), FBSDprivate_1.0) + static sem_t sem_alloc(unsigned int value, semid_t semid, int system_sem); static void sem_free(sem_t sem); -static LIST_HEAD(, sem) named_sems = LIST_HEAD_INITIALIZER(named_sems); +static LIST_HEAD(, sem) named_sems = LIST_HEAD_INITIALIZER(&named_sems); static pthread_mutex_t named_sems_mtx = PTHREAD_MUTEX_INITIALIZER; -__weak_reference(__sem_init, sem_init); -__weak_reference(__sem_destroy, sem_destroy); -__weak_reference(__sem_open, sem_open); -__weak_reference(__sem_close, sem_close); -__weak_reference(__sem_unlink, sem_unlink); -__weak_reference(__sem_wait, sem_wait); -__weak_reference(__sem_trywait, sem_trywait); -__weak_reference(__sem_timedwait, sem_timedwait); -__weak_reference(__sem_post, sem_post); -__weak_reference(__sem_getvalue, sem_getvalue); - +FB10_COMPAT(_libc_sem_init_compat, sem_init); +FB10_COMPAT(_libc_sem_destroy_compat, sem_destroy); +FB10_COMPAT(_libc_sem_open_compat, sem_open); +FB10_COMPAT(_libc_sem_close_compat, sem_close); +FB10_COMPAT(_libc_sem_unlink_compat, sem_unlink); +FB10_COMPAT(_libc_sem_wait_compat, sem_wait); +FB10_COMPAT(_libc_sem_trywait_compat, sem_trywait); +FB10_COMPAT(_libc_sem_timedwait_compat, sem_timedwait); +FB10_COMPAT(_libc_sem_post_compat, sem_post); +FB10_COMPAT(_libc_sem_getvalue_compat, sem_getvalue); static inline int sem_check_validity(sem_t *sem) @@ -104,8 +142,6 @@ static void sem_free(sem_t sem) { - _pthread_mutex_destroy(&sem->lock); - _pthread_cond_destroy(&sem->gtzero); sem->magic = 0; free(sem); } @@ -131,13 +167,11 @@ sem_alloc(unsigned int value, semid_t semid, int system_sem) sem->magic = SEM_MAGIC; sem->semid = semid; sem->syssem = system_sem; - sem->lock = PTHREAD_MUTEX_INITIALIZER; - sem->gtzero = PTHREAD_COND_INITIALIZER; return (sem); } int -__sem_init(sem_t *sem, int pshared, unsigned int value) +_libc_sem_init_compat(sem_t *sem, int pshared, unsigned int value) { semid_t semid; @@ -147,26 +181,27 @@ __sem_init(sem_t *sem, int pshared, unsigned int value) * pthread_cond_wait() is just a stub that doesn't really * wait. */ - if (ksem_init(&semid, value) != 0) + semid = (semid_t)SEM_USER; + if ((pshared != 0) && ksem_init(&semid, value) != 0) return (-1); - (*sem) = sem_alloc(value, semid, 1); + *sem = sem_alloc(value, semid, pshared); if ((*sem) == NULL) { - ksem_destroy(semid); + if (pshared != 0) + ksem_destroy(semid); return (-1); } return (0); } int -__sem_destroy(sem_t *sem) +_libc_sem_destroy_compat(sem_t *sem) { int retval; if (sem_check_validity(sem) != 0) return (-1); - _pthread_mutex_lock(&(*sem)->lock); /* * If this is a system semaphore let the kernel track it otherwise * make sure there are no waiters. @@ -181,18 +216,14 @@ __sem_destroy(sem_t *sem) retval = 0; (*sem)->magic = 0; } - _pthread_mutex_unlock(&(*sem)->lock); - if (retval == 0) { - _pthread_mutex_destroy(&(*sem)->lock); - _pthread_cond_destroy(&(*sem)->gtzero); + if (retval == 0) sem_free(*sem); - } return (retval); } sem_t * -__sem_open(const char *name, int oflag, ...) +_libc_sem_open_compat(const char *name, int oflag, ...) { sem_t *sem; sem_t s; @@ -255,7 +286,7 @@ err: } int -__sem_close(sem_t *sem) +_libc_sem_close_compat(sem_t *sem) { if (sem_check_validity(sem) != 0) @@ -280,68 +311,156 @@ __sem_close(sem_t *sem) } int -__sem_unlink(const char *name) +_libc_sem_unlink_compat(const char *name) { return (ksem_unlink(name)); } -int -__sem_wait(sem_t *sem) +static int +enable_async_cancel(void) { + int old; - if (sem_check_validity(sem) != 0) + _pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old); + return (old); +} + +static void +restore_async_cancel(int val) +{ + _pthread_setcanceltype(val, NULL); +} + +static int +_umtx_wait_uint(volatile unsigned *mtx, unsigned id, const struct timespec *timeout) +{ + if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 && + timeout->tv_nsec <= 0))) { + errno = ETIMEDOUT; return (-1); + } + return _umtx_op(__DEVOLATILE(void *, mtx), + UMTX_OP_WAIT_UINT_PRIVATE, id, NULL, __DECONST(void*, timeout)); +} - return (ksem_wait((*sem)->semid)); +static int +_umtx_wake(volatile void *mtx) +{ + return _umtx_op(__DEVOLATILE(void *, mtx), UMTX_OP_WAKE_PRIVATE, + 1, NULL, NULL); +} + +#define TIMESPEC_SUB(dst, src, val) \ + do { \ + (dst)->tv_sec = (src)->tv_sec - (val)->tv_sec; \ + (dst)->tv_nsec = (src)->tv_nsec - (val)->tv_nsec; \ + if ((dst)->tv_nsec < 0) { \ + (dst)->tv_sec--; \ + (dst)->tv_nsec += 1000000000; \ + } \ + } while (0) + + +static void +sem_cancel_handler(void *arg) +{ + sem_t *sem = arg; + + atomic_add_int(&(*sem)->nwaiters, -1); + if ((*sem)->nwaiters && (*sem)->count) + _umtx_wake(&(*sem)->count); } int -__sem_trywait(sem_t *sem) +_libc_sem_timedwait_compat(sem_t * __restrict sem, + const struct timespec * __restrict abstime) { - int retval; + struct timespec ts, ts2; + int val, retval, saved_cancel; if (sem_check_validity(sem) != 0) return (-1); - if ((*sem)->syssem != 0) - retval = ksem_trywait((*sem)->semid); - else { - _pthread_mutex_lock(&(*sem)->lock); - if ((*sem)->count > 0) { - (*sem)->count--; - retval = 0; - } else { - errno = EAGAIN; - retval = -1; + if ((*sem)->syssem != 0) { + saved_cancel = enable_async_cancel(); + retval = ksem_wait((*sem)->semid); + restore_async_cancel(saved_cancel); + return (retval); + } + + retval = 0; + _pthread_testcancel(); + for (;;) { + while ((val = (*sem)->count) > 0) { + if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) + return (0); + } + if (retval) + break; + if (abstime) { + if (abstime->tv_nsec >= 1000000000 || abstime->tv_nsec < 0) { + errno = EINVAL; + return (-1); + } + clock_gettime(CLOCK_REALTIME, &ts); + TIMESPEC_SUB(&ts2, abstime, &ts); } - _pthread_mutex_unlock(&(*sem)->lock); + atomic_add_int(&(*sem)->nwaiters, 1); + pthread_cleanup_push(sem_cancel_handler, sem); + saved_cancel = enable_async_cancel(); + retval = _umtx_wait_uint(&(*sem)->count, 0, abstime ? &ts2 : NULL); + restore_async_cancel(saved_cancel); + pthread_cleanup_pop(0); + atomic_add_int(&(*sem)->nwaiters, -1); } return (retval); } int -__sem_timedwait(sem_t * __restrict sem, - const struct timespec * __restrict abs_timeout) +_libc_sem_wait_compat(sem_t *sem) { + return _libc_sem_timedwait_compat(sem, NULL); +} + +int +_libc_sem_trywait_compat(sem_t *sem) +{ + int val; + if (sem_check_validity(sem) != 0) return (-1); - return (ksem_timedwait((*sem)->semid, abs_timeout)); + if ((*sem)->syssem != 0) + return ksem_trywait((*sem)->semid); + + while ((val = (*sem)->count) > 0) { + if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) + return (0); + } + errno = EAGAIN; + return (-1); } int -__sem_post(sem_t *sem) +_libc_sem_post_compat(sem_t *sem) { if (sem_check_validity(sem) != 0) return (-1); - return (ksem_post((*sem)->semid)); + if ((*sem)->syssem != 0) + return ksem_post((*sem)->semid); + + atomic_add_rel_int(&(*sem)->count, 1); + + if ((*sem)->nwaiters) + return _umtx_wake(&(*sem)->count); + return (0); } int -__sem_getvalue(sem_t * __restrict sem, int * __restrict sval) +_libc_sem_getvalue_compat(sem_t * __restrict sem, int * __restrict sval) { int retval; @@ -351,10 +470,7 @@ __sem_getvalue(sem_t * __restrict sem, int * __restrict sval) if ((*sem)->syssem != 0) retval = ksem_getvalue((*sem)->semid, sval); else { - _pthread_mutex_lock(&(*sem)->lock); *sval = (int)(*sem)->count; - _pthread_mutex_unlock(&(*sem)->lock); - retval = 0; } return (retval); diff --git a/lib/libc/gen/sem_new.c b/lib/libc/gen/sem_new.c new file mode 100644 index 0000000..dac5381 --- /dev/null +++ b/lib/libc/gen/sem_new.c @@ -0,0 +1,470 @@ +/* + * Copyright (C) 2010 David Xu . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include "namespace.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "un-namespace.h" + +__weak_reference(_libc_sem_close, sem_close); +__weak_reference(_libc_sem_close, _sem_close); +__weak_reference(_libc_sem_destroy, sem_destroy); +__weak_reference(_libc_sem_destroy, _sem_destroy); +__weak_reference(_libc_sem_getvalue, sem_getvalue); +__weak_reference(_libc_sem_getvalue, _sem_getvalue); +__weak_reference(_libc_sem_init, sem_init); +__weak_reference(_libc_sem_init, _sem_init); +__weak_reference(_libc_sem_open, sem_open); +__weak_reference(_libc_sem_open, _sem_open); +__weak_reference(_libc_sem_post, sem_post); +__weak_reference(_libc_sem_post, _sem_post); +__weak_reference(_libc_sem_timedwait, sem_timedwait); +__weak_reference(_libc_sem_timedwait, _sem_timedwait); +__weak_reference(_libc_sem_trywait, sem_trywait); +__weak_reference(_libc_sem_trywait, _sem_trywait); +__weak_reference(_libc_sem_unlink, sem_unlink); +__weak_reference(_libc_sem_unlink, _sem_unlink); +__weak_reference(_libc_sem_wait, sem_wait); +__weak_reference(_libc_sem_wait, _sem_wait); + +#define SEM_PREFIX "/tmp/SEMD" +#define SEM_MAGIC ((u_int32_t)0x73656d31) + +struct sem_nameinfo { + int open_count; + char *name; + sem_t *sem; + LIST_ENTRY(sem_nameinfo) next; +}; + +static pthread_once_t once = PTHREAD_ONCE_INIT; +static pthread_mutex_t sem_llock; +static LIST_HEAD(,sem_nameinfo) sem_list = LIST_HEAD_INITIALIZER(sem_list); + +static void +sem_prefork() +{ + + _pthread_mutex_lock(&sem_llock); +} + +static void +sem_postfork() +{ + _pthread_mutex_unlock(&sem_llock); +} + +static void +sem_child_postfork() +{ + _pthread_mutex_unlock(&sem_llock); +} + +static void +sem_module_init(void) +{ + pthread_mutexattr_t ma; + + _pthread_mutexattr_init(&ma); + _pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE); + _pthread_mutex_init(&sem_llock, &ma); + _pthread_mutexattr_destroy(&ma); + _pthread_atfork(sem_prefork, sem_postfork, sem_child_postfork); +} + +static inline int +sem_check_validity(sem_t *sem) +{ + + if (sem->_magic == SEM_MAGIC) + return (0); + else { + errno = EINVAL; + return (-1); + } +} + +int +_libc_sem_init(sem_t *sem, int pshared, unsigned int value) +{ + + if (value > SEM_VALUE_MAX) { + errno = EINVAL; + return (-1); + } + + bzero(sem, sizeof(sem_t)); + sem->_magic = SEM_MAGIC; + sem->_kern._count = (u_int32_t)value; + sem->_kern._has_waiters = 0; + sem->_kern._flags = pshared ? USYNC_PROCESS_SHARED : 0; + return (0); +} + +sem_t * +_libc_sem_open(const char *name, int flags, ...) +{ + char path[PATH_MAX]; + + struct stat sb; + va_list ap; + struct sem_nameinfo *ni = NULL; + sem_t *sem = NULL; + int fd = -1, mode, len; + + if (name[0] != '/') { + errno = EINVAL; + return (NULL); + } + name++; + + if (flags & ~(O_CREAT|O_EXCL)) { + errno = EINVAL; + return (NULL); + } + + _pthread_once(&once, sem_module_init); + + _pthread_mutex_lock(&sem_llock); + LIST_FOREACH(ni, &sem_list, next) { + if (strcmp(name, ni->name) == 0) { + ni->open_count++; + sem = ni->sem; + _pthread_mutex_unlock(&sem_llock); + return (sem); + } + } + + if (flags & O_CREAT) { + va_start(ap, flags); + mode = va_arg(ap, int); + va_end(ap); + } + + len = sizeof(*ni) + strlen(name) + 1; + ni = (struct sem_nameinfo *)malloc(len); + if (ni == NULL) { + errno = ENOSPC; + goto error; + } + + ni->name = (char *)(ni+1); + strcpy(ni->name, name); + + strcpy(path, SEM_PREFIX); + if (strlcat(path, name, sizeof(path)) >= sizeof(path)) { + errno = ENAMETOOLONG; + goto error; + } + + fd = _open(path, flags|O_RDWR, mode); + if (fd == -1) + goto error; + if (flock(fd, LOCK_EX) == -1) + goto error; + if (_fstat(fd, &sb)) { + flock(fd, LOCK_UN); + goto error; + } + if (sb.st_size < sizeof(sem_t)) { + sem_t tmp; + + tmp._magic = SEM_MAGIC; + tmp._kern._has_waiters = 0; + tmp._kern._count = 0; + tmp._kern._flags = USYNC_PROCESS_SHARED | SEM_NAMED; + if (_write(fd, &tmp, sizeof(tmp)) != sizeof(tmp)) { + flock(fd, LOCK_UN); + goto error; + } + } + flock(fd, LOCK_UN); + sem = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ|PROT_WRITE, + MAP_SHARED|MAP_NOSYNC, fd, 0); + if (sem == MAP_FAILED) { + sem = NULL; + if (errno == ENOMEM) + errno = ENOSPC; + goto error; + } + if (sem->_magic != SEM_MAGIC) { + errno = EINVAL; + goto error; + } + ni->open_count = 1; + ni->sem = sem; + LIST_INSERT_HEAD(&sem_list, ni, next); + _pthread_mutex_unlock(&sem_llock); + _close(fd); + return (sem); + +error: + _pthread_mutex_unlock(&sem_llock); + if (fd != -1) + _close(fd); + if (sem != NULL) + munmap(sem, sizeof(sem_t)); + free(ni); + return (SEM_FAILED); +} + +int +_libc_sem_close(sem_t *sem) +{ + struct sem_nameinfo *ni; + + if (sem_check_validity(sem) != 0) + return (-1); + + if (!(sem->_kern._flags & SEM_NAMED)) { + errno = EINVAL; + return (-1); + } + + _pthread_mutex_lock(&sem_llock); + LIST_FOREACH(ni, &sem_list, next) { + if (sem == ni->sem) { + if (--ni->open_count > 0) { + _pthread_mutex_unlock(&sem_llock); + return (0); + } + else + break; + } + } + + if (ni) { + LIST_REMOVE(ni, next); + _pthread_mutex_unlock(&sem_llock); + munmap(sem, sizeof(*sem)); + free(ni); + return (0); + } + _pthread_mutex_unlock(&sem_llock); + return (-1); +} + +int +_libc_sem_unlink(const char *name) +{ + char path[PATH_MAX]; + + if (name[0] != '/') { + errno = ENOENT; + return -1; + } + name++; + + strcpy(path, SEM_PREFIX); + if (strlcat(path, name, sizeof(path)) >= sizeof(path)) { + errno = ENAMETOOLONG; + return (-1); + } + return unlink(path); +} + +int +_libc_sem_destroy(sem_t *sem) +{ + + if (sem_check_validity(sem) != 0) + return (-1); + + if (sem->_kern._flags & SEM_NAMED) { + errno = EINVAL; + return (-1); + } + sem->_magic = 0; + return (0); +} + +int +_libc_sem_getvalue(sem_t * __restrict sem, int * __restrict sval) +{ + + if (sem_check_validity(sem) != 0) + return (-1); + + *sval = (int)sem->_kern._count; + return (0); +} + +static int +usem_wake(struct _usem *sem) +{ + if (!sem->_has_waiters) + return (0); + return _umtx_op(sem, UMTX_OP_SEM_WAKE, 0, NULL, NULL); +} + +static int +usem_wait(struct _usem *sem, const struct timespec *timeout) +{ + if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 && + timeout->tv_nsec <= 0))) { + errno = ETIMEDOUT; + return (-1); + } + return _umtx_op(sem, UMTX_OP_SEM_WAIT, 0, NULL, + __DECONST(void*, timeout)); +} + +int +_libc_sem_trywait(sem_t *sem) +{ + int val; + + if (sem_check_validity(sem) != 0) + return (-1); + + while ((val = sem->_kern._count) > 0) { + if (atomic_cmpset_acq_int(&sem->_kern._count, val, val - 1)) + return (0); + } + errno = EAGAIN; + return (-1); +} + +static void +sem_cancel_handler(void *arg) +{ + sem_t *sem = arg; + + if (sem->_kern._has_waiters && sem->_kern._count) + usem_wake(&sem->_kern); +} + +#define TIMESPEC_SUB(dst, src, val) \ + do { \ + (dst)->tv_sec = (src)->tv_sec - (val)->tv_sec; \ + (dst)->tv_nsec = (src)->tv_nsec - (val)->tv_nsec; \ + if ((dst)->tv_nsec < 0) { \ + (dst)->tv_sec--; \ + (dst)->tv_nsec += 1000000000; \ + } \ + } while (0) + + +static int +enable_async_cancel(void) +{ + int old; + + _pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old); + return (old); +} + +static void +restore_async_cancel(int val) +{ + _pthread_setcanceltype(val, NULL); +} + +int +_libc_sem_timedwait(sem_t * __restrict sem, + const struct timespec * __restrict abstime) +{ + struct timespec ts, ts2; + int val, retval, saved_cancel; + + if (sem_check_validity(sem) != 0) + return (-1); + + retval = 0; + _pthread_testcancel(); + for (;;) { + while ((val = sem->_kern._count) > 0) { + if (atomic_cmpset_acq_int(&sem->_kern._count, val, val - 1)) + return (0); + } + + if (retval) + break; + + /* + * The timeout argument is only supposed to + * be checked if the thread would have blocked. + */ + if (abstime != NULL) { + if (abstime->tv_nsec >= 1000000000 || abstime->tv_nsec < 0) { + errno = EINVAL; + return (-1); + } + clock_gettime(CLOCK_REALTIME, &ts); + TIMESPEC_SUB(&ts2, abstime, &ts); + } + pthread_cleanup_push(sem_cancel_handler, sem); + saved_cancel = enable_async_cancel(); + retval = usem_wait(&sem->_kern, abstime ? &ts2 : NULL); + restore_async_cancel(saved_cancel); + pthread_cleanup_pop(0); + } + return (retval); +} + +int +_libc_sem_wait(sem_t *sem) +{ + return _libc_sem_timedwait(sem, NULL); +} + +/* + * POSIX: + * The sem_post() interface is reentrant with respect to signals and may be + * invoked from a signal-catching function. + * The implementation does not use lock, so it should be safe. + */ +int +_libc_sem_post(sem_t *sem) +{ + + if (sem_check_validity(sem) != 0) + return (-1); + + atomic_add_rel_int(&sem->_kern._count, 1); + if (sem->_kern._has_waiters) + return usem_wake(&sem->_kern); + return (0); +} diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h index 052eb13..cb0b407 100644 --- a/lib/libc/include/libc_private.h +++ b/lib/libc/include/libc_private.h @@ -127,6 +127,8 @@ typedef enum { PJT_SETSPECIFIC, PJT_SIGMASK, PJT_TESTCANCEL, + PJT_CLEANUP_POP_IMP, + PJT_CLEANUP_PUSH_IMP, PJT_MAX } pjt_index_t; -- cgit v1.1 From 8ea6a66616580dbd388bcbc17ab0def79d86724f Mon Sep 17 00:00:00 2001 From: davidxu Date: Tue, 5 Jan 2010 03:39:31 +0000 Subject: Don't check has_waiters twice, inline some small functions. performance result on my machine: mutex Elapsed: 902115 us; per iteration: 90 ns. semaphore Elapsed: 958780 us; per iteration: 95 ns. --- lib/libc/gen/sem_new.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/sem_new.c b/lib/libc/gen/sem_new.c index dac5381..844be28 100644 --- a/lib/libc/gen/sem_new.c +++ b/lib/libc/gen/sem_new.c @@ -331,7 +331,7 @@ _libc_sem_getvalue(sem_t * __restrict sem, int * __restrict sval) return (0); } -static int +static __inline int usem_wake(struct _usem *sem) { if (!sem->_has_waiters) @@ -339,7 +339,7 @@ usem_wake(struct _usem *sem) return _umtx_op(sem, UMTX_OP_SEM_WAKE, 0, NULL, NULL); } -static int +static __inline int usem_wait(struct _usem *sem, const struct timespec *timeout) { if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 && @@ -387,7 +387,7 @@ sem_cancel_handler(void *arg) } while (0) -static int +static __inline int enable_async_cancel(void) { int old; @@ -396,7 +396,7 @@ enable_async_cancel(void) return (old); } -static void +static __inline void restore_async_cancel(int val) { _pthread_setcanceltype(val, NULL); @@ -413,7 +413,6 @@ _libc_sem_timedwait(sem_t * __restrict sem, return (-1); retval = 0; - _pthread_testcancel(); for (;;) { while ((val = sem->_kern._count) > 0) { if (atomic_cmpset_acq_int(&sem->_kern._count, val, val - 1)) @@ -464,7 +463,5 @@ _libc_sem_post(sem_t *sem) return (-1); atomic_add_rel_int(&sem->_kern._count, 1); - if (sem->_kern._has_waiters) - return usem_wake(&sem->_kern); - return (0); + return usem_wake(&sem->_kern); } -- cgit v1.1 From d3f9024243e0e9abf6686ec65b4cdea3ac8d834c Mon Sep 17 00:00:00 2001 From: davidxu Date: Tue, 5 Jan 2010 05:44:52 +0000 Subject: Remove unused macros. --- lib/libc/gen/sem.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/sem.c b/lib/libc/gen/sem.c index 4ec7890..65c3424 100644 --- a/lib/libc/gen/sem.c +++ b/lib/libc/gen/sem.c @@ -99,16 +99,11 @@ typedef struct sem* sem_t; #define SYM_FBP10(sym) __CONCAT(sym, _fbp10) #define WEAK_REF(sym, alias) __weak_reference(sym, alias) #define SYM_COMPAT(sym, impl, ver) __sym_compat(sym, impl, ver) -#define SYM_DEFAULT(sym, impl, ver) __sym_default(sym, impl, ver) #define FB10_COMPAT(func, sym) \ WEAK_REF(func, SYM_FB10(sym)); \ SYM_COMPAT(sym, SYM_FB10(sym), FBSD_1.0) -#define FB10_COMPAT_PRIVATE(func, sym) \ - WEAK_REF(func, SYM_FBP10(sym)); \ - SYM_DEFAULT(sym, SYM_FBP10(sym), FBSDprivate_1.0) - static sem_t sem_alloc(unsigned int value, semid_t semid, int system_sem); static void sem_free(sem_t sem); -- cgit v1.1 From a3e15a64d4ce0e58d1229c68414a924c202202d8 Mon Sep 17 00:00:00 2001 From: davidxu Date: Tue, 5 Jan 2010 05:47:18 +0000 Subject: forgot to remove SYM_FBP10. ;-) --- lib/libc/gen/sem.c | 1 - 1 file changed, 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/sem.c b/lib/libc/gen/sem.c index 65c3424..7cb021c 100644 --- a/lib/libc/gen/sem.c +++ b/lib/libc/gen/sem.c @@ -96,7 +96,6 @@ typedef struct sem* sem_t; #define SEM_VALUE_MAX __INT_MAX #define SYM_FB10(sym) __CONCAT(sym, _fb10) -#define SYM_FBP10(sym) __CONCAT(sym, _fbp10) #define WEAK_REF(sym, alias) __weak_reference(sym, alias) #define SYM_COMPAT(sym, impl, ver) __sym_compat(sym, impl, ver) -- cgit v1.1 From 3f563b5b5f32331253c1c28a711d5d3e3896f2a1 Mon Sep 17 00:00:00 2001 From: davidxu Date: Tue, 5 Jan 2010 06:40:27 +0000 Subject: More cleanup, remove _libc prefix because libthr no longer has stubs referencing them. --- lib/libc/gen/Symbol.map | 8 -------- lib/libc/gen/sem_new.c | 52 ++++++++++++++++++++----------------------------- 2 files changed, 21 insertions(+), 39 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index 4f75b73..e7d59bb 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -475,14 +475,6 @@ FBSDprivate_1.0 { __waitpid; _waitpid; - _libc_sem_destroy; - _libc_sem_init; - _libc_sem_getvalue; - _libc_sem_trywait; - _libc_sem_wait; - _libc_sem_timedwait; - _libc_sem_post; - _libc_sem_init_compat; _libc_sem_destroy_compat; _libc_sem_open_compat; diff --git a/lib/libc/gen/sem_new.c b/lib/libc/gen/sem_new.c index 844be28..dbaf6e1 100644 --- a/lib/libc/gen/sem_new.c +++ b/lib/libc/gen/sem_new.c @@ -48,26 +48,16 @@ #include #include "un-namespace.h" -__weak_reference(_libc_sem_close, sem_close); -__weak_reference(_libc_sem_close, _sem_close); -__weak_reference(_libc_sem_destroy, sem_destroy); -__weak_reference(_libc_sem_destroy, _sem_destroy); -__weak_reference(_libc_sem_getvalue, sem_getvalue); -__weak_reference(_libc_sem_getvalue, _sem_getvalue); -__weak_reference(_libc_sem_init, sem_init); -__weak_reference(_libc_sem_init, _sem_init); -__weak_reference(_libc_sem_open, sem_open); -__weak_reference(_libc_sem_open, _sem_open); -__weak_reference(_libc_sem_post, sem_post); -__weak_reference(_libc_sem_post, _sem_post); -__weak_reference(_libc_sem_timedwait, sem_timedwait); -__weak_reference(_libc_sem_timedwait, _sem_timedwait); -__weak_reference(_libc_sem_trywait, sem_trywait); -__weak_reference(_libc_sem_trywait, _sem_trywait); -__weak_reference(_libc_sem_unlink, sem_unlink); -__weak_reference(_libc_sem_unlink, _sem_unlink); -__weak_reference(_libc_sem_wait, sem_wait); -__weak_reference(_libc_sem_wait, _sem_wait); +__weak_reference(_sem_close, sem_close); +__weak_reference(_sem_destroy, sem_destroy); +__weak_reference(_sem_getvalue, sem_getvalue); +__weak_reference(_sem_init, sem_init); +__weak_reference(_sem_open, sem_open); +__weak_reference(_sem_post, sem_post); +__weak_reference(_sem_timedwait, sem_timedwait); +__weak_reference(_sem_trywait, sem_trywait); +__weak_reference(_sem_unlink, sem_unlink); +__weak_reference(_sem_wait, sem_wait); #define SEM_PREFIX "/tmp/SEMD" #define SEM_MAGIC ((u_int32_t)0x73656d31) @@ -127,7 +117,7 @@ sem_check_validity(sem_t *sem) } int -_libc_sem_init(sem_t *sem, int pshared, unsigned int value) +_sem_init(sem_t *sem, int pshared, unsigned int value) { if (value > SEM_VALUE_MAX) { @@ -144,7 +134,7 @@ _libc_sem_init(sem_t *sem, int pshared, unsigned int value) } sem_t * -_libc_sem_open(const char *name, int flags, ...) +_sem_open(const char *name, int flags, ...) { char path[PATH_MAX]; @@ -251,7 +241,7 @@ error: } int -_libc_sem_close(sem_t *sem) +_sem_close(sem_t *sem) { struct sem_nameinfo *ni; @@ -287,7 +277,7 @@ _libc_sem_close(sem_t *sem) } int -_libc_sem_unlink(const char *name) +_sem_unlink(const char *name) { char path[PATH_MAX]; @@ -306,7 +296,7 @@ _libc_sem_unlink(const char *name) } int -_libc_sem_destroy(sem_t *sem) +_sem_destroy(sem_t *sem) { if (sem_check_validity(sem) != 0) @@ -321,7 +311,7 @@ _libc_sem_destroy(sem_t *sem) } int -_libc_sem_getvalue(sem_t * __restrict sem, int * __restrict sval) +_sem_getvalue(sem_t * __restrict sem, int * __restrict sval) { if (sem_check_validity(sem) != 0) @@ -352,7 +342,7 @@ usem_wait(struct _usem *sem, const struct timespec *timeout) } int -_libc_sem_trywait(sem_t *sem) +_sem_trywait(sem_t *sem) { int val; @@ -403,7 +393,7 @@ restore_async_cancel(int val) } int -_libc_sem_timedwait(sem_t * __restrict sem, +_sem_timedwait(sem_t * __restrict sem, const struct timespec * __restrict abstime) { struct timespec ts, ts2; @@ -444,9 +434,9 @@ _libc_sem_timedwait(sem_t * __restrict sem, } int -_libc_sem_wait(sem_t *sem) +_sem_wait(sem_t *sem) { - return _libc_sem_timedwait(sem, NULL); + return _sem_timedwait(sem, NULL); } /* @@ -456,7 +446,7 @@ _libc_sem_wait(sem_t *sem) * The implementation does not use lock, so it should be safe. */ int -_libc_sem_post(sem_t *sem) +_sem_post(sem_t *sem) { if (sem_check_validity(sem) != 0) -- cgit v1.1 From bdeb978682602f230c0327f6bc99de24fce20ec0 Mon Sep 17 00:00:00 2001 From: brueffer Date: Tue, 5 Jan 2010 20:18:41 +0000 Subject: Fix a double free(). PR: 142339 Submitted by: Henning Petersen MFC after: 2 weeks --- lib/libc/rpc/getnetpath.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/rpc/getnetpath.c b/lib/libc/rpc/getnetpath.c index 0563544..d1ea554 100644 --- a/lib/libc/rpc/getnetpath.c +++ b/lib/libc/rpc/getnetpath.c @@ -101,7 +101,7 @@ setnetpath() if ((np_sessionp->nc_handlep = setnetconfig()) == NULL) { free(np_sessionp); syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); - goto failed; + return (NULL); } np_sessionp->valid = NP_VALID; np_sessionp->ncp_list = NULL; -- cgit v1.1 From 95ccd2a39d6e19b8cdffca8356395ffed863a8b6 Mon Sep 17 00:00:00 2001 From: kib Date: Tue, 5 Jan 2010 20:20:31 +0000 Subject: Do not rely on behaviour undefined by ANSI C, use thunks to adapt alphasort-like interface to the comparision function required by qsort() and qsort_r(). For opendir() thunk and alphasort(), comment on why we deviated from POSIX by using strcmp() instead of strcoll(). Requested and reviewed by: bde MFC after: 2 weeks --- lib/libc/gen/opendir.c | 16 ++++++++++++++-- lib/libc/gen/scandir.c | 21 +++++++++++++++++++-- 2 files changed, 33 insertions(+), 4 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/opendir.c b/lib/libc/gen/opendir.c index 631c4d6..c192ab2 100644 --- a/lib/libc/gen/opendir.c +++ b/lib/libc/gen/opendir.c @@ -93,6 +93,18 @@ __opendir2(const char *name, int flags) } /* + * POSIX 2008 and XSI 7 require alphasort() to call strcoll() for + * directory entries ordering. Use local copy that uses strcmp(). + */ +static int +opendir_alphasort(const void *p1, const void *p2) +{ + + return (strcmp((*(const struct dirent **)p1)->d_name, + (*(const struct dirent **)p2)->d_name)); +} + +/* * Common routine for opendir(3), __opendir2(3) and fdopendir(3). */ static DIR * @@ -240,8 +252,8 @@ __opendir_common(int fd, const char *name, int flags) /* * This sort must be stable. */ - mergesort(dpv, n, sizeof(*dpv), (int (*)(const - void *, const void *))alphasort); + mergesort(dpv, n, sizeof(*dpv), + opendir_alphasort); dpv[n] = NULL; xp = NULL; diff --git a/lib/libc/gen/scandir.c b/lib/libc/gen/scandir.c index 47fad1d..b6f76ba 100644 --- a/lib/libc/gen/scandir.c +++ b/lib/libc/gen/scandir.c @@ -46,6 +46,8 @@ __FBSDID("$FreeBSD$"); #include #include "un-namespace.h" +static int alphasort_thunk(void *thunk, const void *p1, const void *p2); + /* * The DIRSIZ macro is the minimum record length which will hold the directory * entry. This requires the amount of space in struct dirent without the @@ -109,8 +111,8 @@ scandir(const char *dirname, struct dirent ***namelist, } closedir(dirp); if (nitems && dcomp != NULL) - qsort(names, nitems, sizeof(struct dirent *), - (int (*)(const void *, const void *))dcomp); + qsort_r(names, nitems, sizeof(struct dirent *), + &dcomp, alphasort_thunk); *namelist = names; return (nitems); @@ -124,6 +126,12 @@ fail: /* * Alphabetic order comparison routine for those who want it. + * + * XXXKIB POSIX 2008 requires the alphasort() to use strcoll(). Keep + * strcmp() for now, since environment locale settings could have no + * relevance for the byte sequence of the file name. Moreover, it + * might be even invalid sequence in current locale, and then + * behaviour of alphasort would be undefined. */ int alphasort(const struct dirent **d1, const struct dirent **d2) @@ -131,3 +139,12 @@ alphasort(const struct dirent **d1, const struct dirent **d2) return (strcmp((*d1)->d_name, (*d2)->d_name)); } + +static int +alphasort_thunk(void *thunk, const void *p1, const void *p2) +{ + int (*dc)(const struct dirent **, const struct dirent **); + + dc = *(int (**)(const struct dirent **, const struct dirent **))thunk; + return (dc((const struct dirent **)p1, (const struct dirent **)p2)); +} -- cgit v1.1 From 52e7326f46b47766fdce0daed63d650df8e3e576 Mon Sep 17 00:00:00 2001 From: jhb Date: Wed, 6 Jan 2010 20:43:40 +0000 Subject: Use _pthread_once() rather than _once() for localtime() and gmtime(). These methods are only invoked when __isthreaded is true at which point it is safe to use _pthread_once() directly. MFC after: 1 week --- lib/libc/stdtime/localtime.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdtime/localtime.c b/lib/libc/stdtime/localtime.c index ad26f7e..bee916b 100644 --- a/lib/libc/stdtime/localtime.c +++ b/lib/libc/stdtime/localtime.c @@ -1426,7 +1426,7 @@ const time_t * const timep; struct tm *p_tm; if (__isthreaded != 0) { - _once(&localtime_once, localtime_key_init); + _pthread_once(&localtime_once, localtime_key_init); if (localtime_key_error != 0) { errno = localtime_key_error; return(NULL); @@ -1527,7 +1527,7 @@ const time_t * const timep; struct tm *p_tm; if (__isthreaded != 0) { - _once(&gmtime_once, gmtime_key_init); + _pthread_once(&gmtime_once, gmtime_key_init); if (gmtime_key_error != 0) { errno = gmtime_key_error; return(NULL); -- cgit v1.1 From d206161359d96c0b5fb300d4243de94c7c0780eb Mon Sep 17 00:00:00 2001 From: davidxu Date: Thu, 7 Jan 2010 04:15:49 +0000 Subject: Don't forget to use fourth argument if O_CREAT is set in argument oflag. The fourth specifies initial value for the semaphore. --- lib/libc/gen/sem_new.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/sem_new.c b/lib/libc/gen/sem_new.c index dbaf6e1..a4bb4f3 100644 --- a/lib/libc/gen/sem_new.c +++ b/lib/libc/gen/sem_new.c @@ -143,6 +143,7 @@ _sem_open(const char *name, int flags, ...) struct sem_nameinfo *ni = NULL; sem_t *sem = NULL; int fd = -1, mode, len; + int value = 0; if (name[0] != '/') { errno = EINVAL; @@ -170,6 +171,7 @@ _sem_open(const char *name, int flags, ...) if (flags & O_CREAT) { va_start(ap, flags); mode = va_arg(ap, int); + value = va_arg(ap, int); va_end(ap); } @@ -203,7 +205,7 @@ _sem_open(const char *name, int flags, ...) tmp._magic = SEM_MAGIC; tmp._kern._has_waiters = 0; - tmp._kern._count = 0; + tmp._kern._count = value; tmp._kern._flags = USYNC_PROCESS_SHARED | SEM_NAMED; if (_write(fd, &tmp, sizeof(tmp)) != sizeof(tmp)) { flock(fd, LOCK_UN); -- cgit v1.1 From fe8ccb0bf3097cfe7df2a8e79774b7d216993368 Mon Sep 17 00:00:00 2001 From: kib Date: Thu, 7 Jan 2010 13:31:00 +0000 Subject: Give some information on SF_MNOWAIT flag. MFC after: 3 days --- lib/libc/sys/sendfile.2 | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/sys/sendfile.2 b/lib/libc/sys/sendfile.2 index 322971f..612ff5c 100644 --- a/lib/libc/sys/sendfile.2 +++ b/lib/libc/sys/sendfile.2 @@ -116,9 +116,17 @@ Busy servers may benefit by transferring requests that would block to a separate I/O worker thread. .It .Dv SF_MNOWAIT . -(description missing) +Do not wait for some kernel resource to become available, +in particular, +.Vt mbuf +and +.Vt sf_buf . +The flag does not make the +.Fn sendfile +syscall trully non-blocking, since other resources are still allocated +in blocking fashion. .It -.Dv SF_SYNC , +.Dv SF_SYNC . .Nm sleeps until the network stack no longer references the VM pages of the file, making subsequent modifications to it safe. -- cgit v1.1 From d121f05cac6a6999edd08af7917ea45996a04216 Mon Sep 17 00:00:00 2001 From: trasz Date: Thu, 7 Jan 2010 16:52:00 +0000 Subject: Remove BUGS section that no longer applies after recent changes to semaphore code. OK-ed by: davidxu --- lib/libc/gen/sem_init.3 | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/sem_init.3 b/lib/libc/gen/sem_init.3 index 202612a..5938f2c 100644 --- a/lib/libc/gen/sem_init.3 +++ b/lib/libc/gen/sem_init.3 @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 8, 2009 +.Dd January 7, 2010 .Dt SEM_INIT 3 .Os .Sh NAME @@ -90,10 +90,3 @@ The .Fn sem_init function conforms to .St -p1003.1-96 . -.Sh BUGS -A sem_t is a pointer to a separately allocated structure, -therefore process shared semaphores only work between related processes -and do not perform very well -(each operation is a system call, -while single-process semaphores only do a system call -if they need to block or wake up a thread). -- cgit v1.1 From ad6b20aa0f7f596e1e8cdc9adfd6108cd033dadb Mon Sep 17 00:00:00 2001 From: brueffer Date: Thu, 7 Jan 2010 21:08:22 +0000 Subject: Fix a typo and bump date for the previous commit. --- lib/libc/sys/sendfile.2 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/sys/sendfile.2 b/lib/libc/sys/sendfile.2 index 612ff5c..1c1bf8e 100644 --- a/lib/libc/sys/sendfile.2 +++ b/lib/libc/sys/sendfile.2 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 24, 2006 +.Dd January 7, 2010 .Dt SENDFILE 2 .Os .Sh NAME @@ -123,7 +123,7 @@ and .Vt sf_buf . The flag does not make the .Fn sendfile -syscall trully non-blocking, since other resources are still allocated +syscall truly non-blocking, since other resources are still allocated in blocking fashion. .It .Dv SF_SYNC . -- cgit v1.1 From c80db57072dca0591b650a20b415489715827e7f Mon Sep 17 00:00:00 2001 From: kib Date: Thu, 7 Jan 2010 21:14:46 +0000 Subject: Further fix grammar. Suggested by: alc MFC after: 3 days --- lib/libc/sys/sendfile.2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/sys/sendfile.2 b/lib/libc/sys/sendfile.2 index 1c1bf8e..d9f8cab 100644 --- a/lib/libc/sys/sendfile.2 +++ b/lib/libc/sys/sendfile.2 @@ -124,7 +124,7 @@ and The flag does not make the .Fn sendfile syscall truly non-blocking, since other resources are still allocated -in blocking fashion. +in a blocking fashion. .It .Dv SF_SYNC . .Nm -- cgit v1.1 From ca938e57e7490deb967828949eb8d4b9f90bd349 Mon Sep 17 00:00:00 2001 From: brueffer Date: Fri, 8 Jan 2010 22:02:42 +0000 Subject: Remove unnecessary quoting and markup, add missing punctuation. PR: 140494 Submitted by: Jeremy Huddleston , bde MFC after: 1 week --- lib/libc/stdio/getc.3 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdio/getc.3 b/lib/libc/stdio/getc.3 index c8b9386..d0f3c15 100644 --- a/lib/libc/stdio/getc.3 +++ b/lib/libc/stdio/getc.3 @@ -56,7 +56,7 @@ .Ft int .Fn getchar void .Ft int -.Fn getchar_unlocked "void" +.Fn getchar_unlocked void .Ft int .Fn getw "FILE *stream" .Sh DESCRIPTION @@ -141,7 +141,7 @@ until the condition is cleared with .Sh STANDARDS The .Fn fgetc , -.Fn getc +.Fn getc , and .Fn getchar functions @@ -167,4 +167,3 @@ The size and byte order of an varies from one machine to another, and .Fn getw is not recommended for portable applications. -.Pp -- cgit v1.1 From 5bd0838ff59a038135c0149516fae77be123eb31 Mon Sep 17 00:00:00 2001 From: imp Date: Fri, 8 Jan 2010 23:50:39 +0000 Subject: Merge r195025 from projects/mips to head by hand: r195025 | gonzo | 2009-06-25 19:01:50 -0600 (Thu, 25 Jun 2009) | 4 lines - Move fpgetXXX.c/fpsetXXX.c sources to hardfloat subdir/ to prevenmt them from being mixed up with lib/libc/softfloat files with the same names --- lib/libc/mips/gen/fpgetmask.c | 29 ----------------------- lib/libc/mips/gen/fpgetround.c | 29 ----------------------- lib/libc/mips/gen/fpgetsticky.c | 29 ----------------------- lib/libc/mips/gen/fpsetmask.c | 38 ------------------------------- lib/libc/mips/gen/fpsetround.c | 37 ------------------------------ lib/libc/mips/gen/fpsetsticky.c | 38 ------------------------------- lib/libc/mips/gen/hardfloat/fpgetmask.c | 29 +++++++++++++++++++++++ lib/libc/mips/gen/hardfloat/fpgetround.c | 29 +++++++++++++++++++++++ lib/libc/mips/gen/hardfloat/fpgetsticky.c | 29 +++++++++++++++++++++++ lib/libc/mips/gen/hardfloat/fpsetmask.c | 38 +++++++++++++++++++++++++++++++ lib/libc/mips/gen/hardfloat/fpsetround.c | 37 ++++++++++++++++++++++++++++++ lib/libc/mips/gen/hardfloat/fpsetsticky.c | 38 +++++++++++++++++++++++++++++++ 12 files changed, 200 insertions(+), 200 deletions(-) delete mode 100644 lib/libc/mips/gen/fpgetmask.c delete mode 100644 lib/libc/mips/gen/fpgetround.c delete mode 100644 lib/libc/mips/gen/fpgetsticky.c delete mode 100644 lib/libc/mips/gen/fpsetmask.c delete mode 100644 lib/libc/mips/gen/fpsetround.c delete mode 100644 lib/libc/mips/gen/fpsetsticky.c create mode 100644 lib/libc/mips/gen/hardfloat/fpgetmask.c create mode 100644 lib/libc/mips/gen/hardfloat/fpgetround.c create mode 100644 lib/libc/mips/gen/hardfloat/fpgetsticky.c create mode 100644 lib/libc/mips/gen/hardfloat/fpsetmask.c create mode 100644 lib/libc/mips/gen/hardfloat/fpsetround.c create mode 100644 lib/libc/mips/gen/hardfloat/fpsetsticky.c (limited to 'lib/libc') diff --git a/lib/libc/mips/gen/fpgetmask.c b/lib/libc/mips/gen/fpgetmask.c deleted file mode 100644 index 505a74c..0000000 --- a/lib/libc/mips/gen/fpgetmask.c +++ /dev/null @@ -1,29 +0,0 @@ -/* $NetBSD: fpgetmask.c,v 1.5 2005/12/24 23:10:08 perry Exp $ */ - -/* - * Written by J.T. Conklin, Apr 11, 1995 - * Public domain. - */ - -#include -__FBSDID("$FreeBSD$"); -#if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: fpgetmask.c,v 1.5 2005/12/24 23:10:08 perry Exp $"); -#endif /* LIBC_SCCS and not lint */ - -#include "namespace.h" - -#include - -#ifdef __weak_alias -__weak_alias(fpgetmask,_fpgetmask) -#endif - -fp_except_t -fpgetmask() -{ - int x; - - __asm("cfc1 %0,$31" : "=r" (x)); - return (x >> 7) & 0x1f; -} diff --git a/lib/libc/mips/gen/fpgetround.c b/lib/libc/mips/gen/fpgetround.c deleted file mode 100644 index 6d0f11a..0000000 --- a/lib/libc/mips/gen/fpgetround.c +++ /dev/null @@ -1,29 +0,0 @@ -/* $NetBSD: fpgetround.c,v 1.5 2005/12/24 23:10:08 perry Exp $ */ - -/* - * Written by J.T. Conklin, Apr 11, 1995 - * Public domain. - */ - -#include -__FBSDID("$FreeBSD$"); -#if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: fpgetround.c,v 1.5 2005/12/24 23:10:08 perry Exp $"); -#endif /* LIBC_SCCS and not lint */ - -#include "namespace.h" - -#include - -#ifdef __weak_alias -__weak_alias(fpgetround,_fpgetround) -#endif - -fp_rnd_t -fpgetround() -{ - int x; - - __asm("cfc1 %0,$31" : "=r" (x)); - return x & 0x03; -} diff --git a/lib/libc/mips/gen/fpgetsticky.c b/lib/libc/mips/gen/fpgetsticky.c deleted file mode 100644 index 8028261..0000000 --- a/lib/libc/mips/gen/fpgetsticky.c +++ /dev/null @@ -1,29 +0,0 @@ -/* $NetBSD: fpgetsticky.c,v 1.5 2005/12/24 23:10:08 perry Exp $ */ - -/* - * Written by J.T. Conklin, Apr 11, 1995 - * Public domain. - */ - -#include -__FBSDID("$FreeBSD$"); -#if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: fpgetsticky.c,v 1.5 2005/12/24 23:10:08 perry Exp $"); -#endif /* LIBC_SCCS and not lint */ - -#include "namespace.h" - -#include - -#ifdef __weak_alias -__weak_alias(fpgetsticky,_fpgetsticky) -#endif - -fp_except_t -fpgetsticky() -{ - int x; - - __asm("cfc1 %0,$31" : "=r" (x)); - return (x >> 2) & 0x1f; -} diff --git a/lib/libc/mips/gen/fpsetmask.c b/lib/libc/mips/gen/fpsetmask.c deleted file mode 100644 index 7abb3fd..0000000 --- a/lib/libc/mips/gen/fpsetmask.c +++ /dev/null @@ -1,38 +0,0 @@ -/* $NetBSD: fpsetmask.c,v 1.5 2005/12/24 23:10:08 perry Exp $ */ - -/* - * Written by J.T. Conklin, Apr 11, 1995 - * Public domain. - */ - -#include -__FBSDID("$FreeBSD$"); -#if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: fpsetmask.c,v 1.5 2005/12/24 23:10:08 perry Exp $"); -#endif /* LIBC_SCCS and not lint */ - -#include "namespace.h" - -#include - -#ifdef __weak_alias -__weak_alias(fpsetmask,_fpsetmask) -#endif - -fp_except_t -fpsetmask(mask) - fp_except_t mask; -{ - fp_except_t old; - fp_except_t new; - - __asm("cfc1 %0,$31" : "=r" (old)); - - new = old; - new &= ~(0x1f << 7); - new |= ((mask & 0x1f) << 7); - - __asm("ctc1 %0,$31" : : "r" (new)); - - return (old >> 7) & 0x1f; -} diff --git a/lib/libc/mips/gen/fpsetround.c b/lib/libc/mips/gen/fpsetround.c deleted file mode 100644 index 0205161..0000000 --- a/lib/libc/mips/gen/fpsetround.c +++ /dev/null @@ -1,37 +0,0 @@ -/* $NetBSD: fpsetround.c,v 1.5 2005/12/24 23:10:08 perry Exp $ */ - -/* - * Written by J.T. Conklin, Apr 11, 1995 - * Public domain. - */ - -#include -__FBSDID("$FreeBSD$"); -#if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: fpsetround.c,v 1.5 2005/12/24 23:10:08 perry Exp $"); -#endif /* LIBC_SCCS and not lint */ - -#include "namespace.h" - -#include - -#ifdef __weak_alias -__weak_alias(fpsetround,_fpsetround) -#endif - -fp_rnd_t -fpsetround(fp_rnd_t rnd_dir) -{ - fp_rnd_t old; - fp_rnd_t new; - - __asm("cfc1 %0,$31" : "=r" (old)); - - new = old; - new &= ~0x03; - new |= (rnd_dir & 0x03); - - __asm("ctc1 %0,$31" : : "r" (new)); - - return old & 0x03; -} diff --git a/lib/libc/mips/gen/fpsetsticky.c b/lib/libc/mips/gen/fpsetsticky.c deleted file mode 100644 index e433671..0000000 --- a/lib/libc/mips/gen/fpsetsticky.c +++ /dev/null @@ -1,38 +0,0 @@ -/* $NetBSD: fpsetsticky.c,v 1.5 2005/12/24 23:10:08 perry Exp $ */ - -/* - * Written by J.T. Conklin, Apr 11, 1995 - * Public domain. - */ - -#include -__FBSDID("$FreeBSD$"); -#if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: fpsetsticky.c,v 1.5 2005/12/24 23:10:08 perry Exp $"); -#endif /* LIBC_SCCS and not lint */ - -#include "namespace.h" - -#include - -#ifdef __weak_alias -__weak_alias(fpsetsticky,_fpsetsticky) -#endif - -fp_except -fpsetsticky(sticky) - fp_except sticky; -{ - fp_except old; - fp_except new; - - __asm("cfc1 %0,$31" : "=r" (old)); - - new = old; - new &= ~(0x1f << 2); - new |= ((sticky & 0x1f) << 2); - - __asm("ctc1 %0,$31" : : "r" (new)); - - return (old >> 2) & 0x1f; -} diff --git a/lib/libc/mips/gen/hardfloat/fpgetmask.c b/lib/libc/mips/gen/hardfloat/fpgetmask.c new file mode 100644 index 0000000..505a74c --- /dev/null +++ b/lib/libc/mips/gen/hardfloat/fpgetmask.c @@ -0,0 +1,29 @@ +/* $NetBSD: fpgetmask.c,v 1.5 2005/12/24 23:10:08 perry Exp $ */ + +/* + * Written by J.T. Conklin, Apr 11, 1995 + * Public domain. + */ + +#include +__FBSDID("$FreeBSD$"); +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: fpgetmask.c,v 1.5 2005/12/24 23:10:08 perry Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#include "namespace.h" + +#include + +#ifdef __weak_alias +__weak_alias(fpgetmask,_fpgetmask) +#endif + +fp_except_t +fpgetmask() +{ + int x; + + __asm("cfc1 %0,$31" : "=r" (x)); + return (x >> 7) & 0x1f; +} diff --git a/lib/libc/mips/gen/hardfloat/fpgetround.c b/lib/libc/mips/gen/hardfloat/fpgetround.c new file mode 100644 index 0000000..6d0f11a --- /dev/null +++ b/lib/libc/mips/gen/hardfloat/fpgetround.c @@ -0,0 +1,29 @@ +/* $NetBSD: fpgetround.c,v 1.5 2005/12/24 23:10:08 perry Exp $ */ + +/* + * Written by J.T. Conklin, Apr 11, 1995 + * Public domain. + */ + +#include +__FBSDID("$FreeBSD$"); +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: fpgetround.c,v 1.5 2005/12/24 23:10:08 perry Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#include "namespace.h" + +#include + +#ifdef __weak_alias +__weak_alias(fpgetround,_fpgetround) +#endif + +fp_rnd_t +fpgetround() +{ + int x; + + __asm("cfc1 %0,$31" : "=r" (x)); + return x & 0x03; +} diff --git a/lib/libc/mips/gen/hardfloat/fpgetsticky.c b/lib/libc/mips/gen/hardfloat/fpgetsticky.c new file mode 100644 index 0000000..8028261 --- /dev/null +++ b/lib/libc/mips/gen/hardfloat/fpgetsticky.c @@ -0,0 +1,29 @@ +/* $NetBSD: fpgetsticky.c,v 1.5 2005/12/24 23:10:08 perry Exp $ */ + +/* + * Written by J.T. Conklin, Apr 11, 1995 + * Public domain. + */ + +#include +__FBSDID("$FreeBSD$"); +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: fpgetsticky.c,v 1.5 2005/12/24 23:10:08 perry Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#include "namespace.h" + +#include + +#ifdef __weak_alias +__weak_alias(fpgetsticky,_fpgetsticky) +#endif + +fp_except_t +fpgetsticky() +{ + int x; + + __asm("cfc1 %0,$31" : "=r" (x)); + return (x >> 2) & 0x1f; +} diff --git a/lib/libc/mips/gen/hardfloat/fpsetmask.c b/lib/libc/mips/gen/hardfloat/fpsetmask.c new file mode 100644 index 0000000..7abb3fd --- /dev/null +++ b/lib/libc/mips/gen/hardfloat/fpsetmask.c @@ -0,0 +1,38 @@ +/* $NetBSD: fpsetmask.c,v 1.5 2005/12/24 23:10:08 perry Exp $ */ + +/* + * Written by J.T. Conklin, Apr 11, 1995 + * Public domain. + */ + +#include +__FBSDID("$FreeBSD$"); +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: fpsetmask.c,v 1.5 2005/12/24 23:10:08 perry Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#include "namespace.h" + +#include + +#ifdef __weak_alias +__weak_alias(fpsetmask,_fpsetmask) +#endif + +fp_except_t +fpsetmask(mask) + fp_except_t mask; +{ + fp_except_t old; + fp_except_t new; + + __asm("cfc1 %0,$31" : "=r" (old)); + + new = old; + new &= ~(0x1f << 7); + new |= ((mask & 0x1f) << 7); + + __asm("ctc1 %0,$31" : : "r" (new)); + + return (old >> 7) & 0x1f; +} diff --git a/lib/libc/mips/gen/hardfloat/fpsetround.c b/lib/libc/mips/gen/hardfloat/fpsetround.c new file mode 100644 index 0000000..0205161 --- /dev/null +++ b/lib/libc/mips/gen/hardfloat/fpsetround.c @@ -0,0 +1,37 @@ +/* $NetBSD: fpsetround.c,v 1.5 2005/12/24 23:10:08 perry Exp $ */ + +/* + * Written by J.T. Conklin, Apr 11, 1995 + * Public domain. + */ + +#include +__FBSDID("$FreeBSD$"); +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: fpsetround.c,v 1.5 2005/12/24 23:10:08 perry Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#include "namespace.h" + +#include + +#ifdef __weak_alias +__weak_alias(fpsetround,_fpsetround) +#endif + +fp_rnd_t +fpsetround(fp_rnd_t rnd_dir) +{ + fp_rnd_t old; + fp_rnd_t new; + + __asm("cfc1 %0,$31" : "=r" (old)); + + new = old; + new &= ~0x03; + new |= (rnd_dir & 0x03); + + __asm("ctc1 %0,$31" : : "r" (new)); + + return old & 0x03; +} diff --git a/lib/libc/mips/gen/hardfloat/fpsetsticky.c b/lib/libc/mips/gen/hardfloat/fpsetsticky.c new file mode 100644 index 0000000..e433671 --- /dev/null +++ b/lib/libc/mips/gen/hardfloat/fpsetsticky.c @@ -0,0 +1,38 @@ +/* $NetBSD: fpsetsticky.c,v 1.5 2005/12/24 23:10:08 perry Exp $ */ + +/* + * Written by J.T. Conklin, Apr 11, 1995 + * Public domain. + */ + +#include +__FBSDID("$FreeBSD$"); +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: fpsetsticky.c,v 1.5 2005/12/24 23:10:08 perry Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#include "namespace.h" + +#include + +#ifdef __weak_alias +__weak_alias(fpsetsticky,_fpsetsticky) +#endif + +fp_except +fpsetsticky(sticky) + fp_except sticky; +{ + fp_except old; + fp_except new; + + __asm("cfc1 %0,$31" : "=r" (old)); + + new = old; + new &= ~(0x1f << 2); + new |= ((sticky & 0x1f) << 2); + + __asm("ctc1 %0,$31" : : "r" (new)); + + return (old >> 2) & 0x1f; +} -- cgit v1.1 From 0ec6bf46abc07cc6f1cd4b328f685d271903c9d8 Mon Sep 17 00:00:00 2001 From: imp Date: Fri, 8 Jan 2010 23:59:04 +0000 Subject: Merge r197800 from projects/mips to head by hand: r197800 | gonzo | 2009-10-06 00:35:52 -0600 (Tue, 06 Oct 2009) | 3 lines - curbrk variable for sbrk and brk should be the same - Add correct variable names to Symbol.map --- lib/libc/mips/Symbol.map | 4 ++-- lib/libc/mips/sys/brk.S | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/mips/Symbol.map b/lib/libc/mips/Symbol.map index 2bbdd6d..c8664eb 100644 --- a/lib/libc/mips/Symbol.map +++ b/lib/libc/mips/Symbol.map @@ -56,8 +56,8 @@ FBSDprivate_1.0 { __siglongjmp; __sys_vfork; _vfork; - end; /* XXX - Should this be _end (see sys/brk.S)? */ - curbrk; + _end; + __curbrk; minbrk; _brk; _sbrk; diff --git a/lib/libc/mips/sys/brk.S b/lib/libc/mips/sys/brk.S index 580d7fa..aeaf791 100644 --- a/lib/libc/mips/sys/brk.S +++ b/lib/libc/mips/sys/brk.S @@ -42,15 +42,12 @@ __FBSDID("$FreeBSD$"); #endif /* LIBC_SCCS and not lint */ .globl _C_LABEL(minbrk) - .globl _C_LABEL(curbrk) + .globl _C_LABEL(__curbrk) .globl _C_LABEL(_end) .data _C_LABEL(minbrk): .word _C_LABEL(_end) -_C_LABEL(curbrk): - .word _C_LABEL(_end) - .text LEAF(__sys_brk) WEAK_ALIAS(brk, __sys_brk) @@ -67,7 +64,7 @@ LEAF(__sys_brk) li v0, SYS_break syscall bne a3, zero, 2f - sw a0, _C_LABEL(curbrk) + sw a0, _C_LABEL(__curbrk) move v0, zero j ra 2: -- cgit v1.1 From f0d3132729cac44d61e22f93e22f6b37fe7c48ae Mon Sep 17 00:00:00 2001 From: imp Date: Sat, 9 Jan 2010 00:01:35 +0000 Subject: Merge r195030 from project/mips to head by hand r195030 | gonzo | 2009-06-25 19:27:31 -0600 (Thu, 25 Jun 2009) | 4 lines - Switch to libc softfloat from libgcc implementation. The problem with latter is that it is not complete, fpsetXXX/fpgetXXX functions are missing. --- lib/libc/Makefile | 2 +- lib/libc/mips/Symbol.map | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/Makefile b/lib/libc/Makefile index 4f13f8e..b58b6cb 100644 --- a/lib/libc/Makefile +++ b/lib/libc/Makefile @@ -64,7 +64,7 @@ NOASM= .include "${.CURDIR}/rpc/Makefile.inc" .include "${.CURDIR}/uuid/Makefile.inc" .include "${.CURDIR}/xdr/Makefile.inc" -.if ${MACHINE_ARCH} == "arm" +.if ${MACHINE_ARCH} == "arm" || ${MACHINE_ARCH} == "mips" .include "${.CURDIR}/softfloat/Makefile.inc" .endif .if ${MK_NIS} != "no" diff --git a/lib/libc/mips/Symbol.map b/lib/libc/mips/Symbol.map index c8664eb..3f24c11 100644 --- a/lib/libc/mips/Symbol.map +++ b/lib/libc/mips/Symbol.map @@ -61,4 +61,22 @@ FBSDprivate_1.0 { minbrk; _brk; _sbrk; + + /* softfloat */ + __addsf3; + __adddf3; + __subsf3; + __subdf3; + __mulsf3; + __muldf3; + __divsf3; + __divdf3; + __floatsisf; + __floatsidf; + __fixsfsi; + __fixdfsi; + __fixunssfsi; + __fixunsdfsi; + __extendsfdf2; + __truncdfsf2; }; -- cgit v1.1 From c74318c2e33ba84d1619a726e45a26870b350fcf Mon Sep 17 00:00:00 2001 From: davidxu Date: Sat, 9 Jan 2010 05:40:46 +0000 Subject: Update manual for sem_init and sem_open, restrictions of shared semaphore and 14 characters in name length no longer exist. Reviewed by: deischen@ --- lib/libc/gen/sem_init.3 | 12 +++++++++++- lib/libc/gen/sem_open.3 | 14 ++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/sem_init.3 b/lib/libc/gen/sem_init.3 index 5938f2c..e00cd4b 100644 --- a/lib/libc/gen/sem_init.3 +++ b/lib/libc/gen/sem_init.3 @@ -46,9 +46,19 @@ function initializes the unnamed semaphore pointed to by .Fa sem to have the value .Fa value . +.Pp A non-zero value for .Fa pshared -specifies a shared semaphore that can be used by multiple processes. +specifies a shared semaphore that can be used by multiple processes, +the semaphore should be located in shared memory region (see +.Xr mmap 2 , +.Xr shm_open 2 , +and +.Xr shmget 2 ) , +any process having read and write access to address +.Fa sem +can perform semaphore operations on +.Fa sem . .Pp Following a successful call to .Fn sem_init , diff --git a/lib/libc/gen/sem_open.3 b/lib/libc/gen/sem_open.3 index 772bdfb..c7ee518 100644 --- a/lib/libc/gen/sem_open.3 +++ b/lib/libc/gen/sem_open.3 @@ -58,6 +58,12 @@ The returned semaphore may be used in subsequent calls to and .Fn sem_close . .Pp +This implementation places strict requirements on the value of +.Fa name : +it must begin with a slash +.Pq Ql / , +contain no other slash characters. +.Pp The following bits may be set in the .Fa oflag argument: @@ -217,11 +223,3 @@ functions conform to .Sh HISTORY Support for named semaphores first appeared in .Fx 5.0 . -.Sh BUGS -This implementation places strict requirements on the value of -.Fa name : -it must begin with a slash -.Pq Ql / , -contain no other slash characters, -and be less than 14 characters in length -not including the terminating null character. -- cgit v1.1 From 6761d75fb415ae7da7b8e184345cf887b384af47 Mon Sep 17 00:00:00 2001 From: delphij Date: Sat, 9 Jan 2010 12:31:11 +0000 Subject: Add a set of manual pages for pthread[_attr]_[sg]etaffinity(3). Reviewed by: davidxu MFC after: 2 weeks --- lib/libc/sys/cpuset.2 | 6 ++++-- lib/libc/sys/cpuset_getaffinity.2 | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/sys/cpuset.2 b/lib/libc/sys/cpuset.2 index fb9a770..1cdff68 100644 --- a/lib/libc/sys/cpuset.2 +++ b/lib/libc/sys/cpuset.2 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 29, 2008 +.Dd January 8, 2010 .Dt CPUSET 2 .Os .Sh NAME @@ -216,7 +216,9 @@ for allocation. .Xr cpuset 1 , .Xr cpuset_getaffinity 2 , .Xr cpuset_setaffinity 2 , -.Xr CPU_SET 3 +.Xr CPU_SET 3 , +.Xr pthread_affinity_np 3 , +.Xr pthread_attr_affinity_np 3 .Sh HISTORY The .Nm diff --git a/lib/libc/sys/cpuset_getaffinity.2 b/lib/libc/sys/cpuset_getaffinity.2 index b065ac3..c8b272f 100644 --- a/lib/libc/sys/cpuset_getaffinity.2 +++ b/lib/libc/sys/cpuset_getaffinity.2 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 29, 2008 +.Dd January 8, 2010 .Dt CPUSET 2 .Os .Sh NAME @@ -147,7 +147,9 @@ operation. .Xr cpuset 2 , .Xr cpuset_getid 2 , .Xr cpuset_setid 2 , -.Xr CPU_SET 3 +.Xr CPU_SET 3 , +.Xr pthread_affinity_np 3 , +.Xr pthread_attr_affinity_np 3 .Sh HISTORY The .Nm -- cgit v1.1 From 0b0c77182599230a7babe401edff4721ba447efd Mon Sep 17 00:00:00 2001 From: brooks Date: Sat, 9 Jan 2010 23:36:51 +0000 Subject: Use the correct types to store uids and gids in the credential cache. --- lib/libc/rpc/svc_auth_des.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/rpc/svc_auth_des.c b/lib/libc/rpc/svc_auth_des.c index 84f1e19..de4d1b4 100644 --- a/lib/libc/rpc/svc_auth_des.c +++ b/lib/libc/rpc/svc_auth_des.c @@ -449,10 +449,10 @@ cache_spot(key, name, timestamp) #define INVALID -1 /* grouplen, if cache entry is invalid */ struct bsdcred { - short uid; /* cached uid */ - short gid; /* cached gid */ - short grouplen; /* length of cached groups */ - short groups[NGROUPS]; /* cached groups */ + uid_t uid; /* cached uid */ + gid_t gid; /* cached gid */ + int grouplen; /* length of cached groups */ + gid_t groups[NGRPS]; /* cached groups */ }; /* -- cgit v1.1 From 030d49b206a72052b076bdf444707e89b797b324 Mon Sep 17 00:00:00 2001 From: cperciva Date: Sun, 10 Jan 2010 14:30:30 +0000 Subject: Give a less silly response to a silly request. Prior to this commit, fread/fwrite calls with size * nmemb > SIZE_MAX were handled by reading or writing (size_t)(size * nmemb) bytes; for example, on 32-bit platforms, fread(ptr, 641, 6700417, f) would read 1 byte and indicate that the requested 6700417 blocks had been read. This commit adds a check for such integer overflows, and treats them as if an overly large request was passed to read/write; i.e., it sets errno to EINVAL, sets the error indicator on the file, and returns a short object count (0, to be specific). The overflow check involves an integer division, so as a performance optimization we check first to see if both size and nmemb are less than 2^16; if they are, no overflow is possible and we avoid the division. We assume here that size_t is at least 32 bits; this appears to be true on all platforms FreeBSD supports. Although this commit fixes an integer overflow, it is not likely to have any security implications, since any program which would be affected by this bug fix is quite clearly already very confused. Reviewed by: kib MFC after: 1 month --- lib/libc/stdio/fread.c | 23 ++++++++++++++++++++++- lib/libc/stdio/fwrite.c | 20 ++++++++++++++++++-- 2 files changed, 40 insertions(+), 3 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdio/fread.c b/lib/libc/stdio/fread.c index 6253856..ad3ea29 100644 --- a/lib/libc/stdio/fread.c +++ b/lib/libc/stdio/fread.c @@ -37,6 +37,8 @@ static char sccsid[] = "@(#)fread.c 8.2 (Berkeley) 12/11/93"; __FBSDID("$FreeBSD$"); #include "namespace.h" +#include +#include #include #include #include "un-namespace.h" @@ -69,8 +71,27 @@ __fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict fp) /* * ANSI and SUSv2 require a return value of 0 if size or count are 0. */ - if ((resid = count * size) == 0) + if ((count == 0) || (size == 0)) return (0); + + /* + * Check for integer overflow. As an optimization, first check that + * at least one of {count, size} is at least 2^16, since if both + * values are less than that, their product can't possible overflow + * (size_t is always at least 32 bits on FreeBSD). + */ + if (((count | size) > 0xFFFF) && + (count > SIZE_MAX / size)) { + errno = EINVAL; + fp->_flags |= __SERR; + return (0); + } + + /* + * Compute the (now required to not overflow) number of bytes to + * read and actually do the work. + */ + resid = count * size; ORIENT(fp, -1); if (fp->_r < 0) fp->_r = 0; diff --git a/lib/libc/stdio/fwrite.c b/lib/libc/stdio/fwrite.c index cf52e42..acac943 100644 --- a/lib/libc/stdio/fwrite.c +++ b/lib/libc/stdio/fwrite.c @@ -37,6 +37,8 @@ static char sccsid[] = "@(#)fwrite.c 8.1 (Berkeley) 6/4/93"; __FBSDID("$FreeBSD$"); #include "namespace.h" +#include +#include #include #include "un-namespace.h" #include "local.h" @@ -60,10 +62,24 @@ fwrite(buf, size, count, fp) /* * ANSI and SUSv2 require a return value of 0 if size or count are 0. */ - n = count * size; - if (n == 0) + if ((count == 0) || (size == 0)) return (0); + /* + * Check for integer overflow. As an optimization, first check that + * at least one of {count, size} is at least 2^16, since if both + * values are less than that, their product can't possible overflow + * (size_t is always at least 32 bits on FreeBSD). + */ + if (((count | size) > 0xFFFF) && + (count > SIZE_MAX / size)) { + errno = EINVAL; + fp->_flags |= __SERR; + return (0); + } + + n = count * size; + iov.iov_base = (void *)buf; uio.uio_resid = iov.iov_len = n; uio.uio_iov = &iov; -- cgit v1.1 From 5d104fe3d7b80ec6fa42b6b91bdfb5c7b24c7775 Mon Sep 17 00:00:00 2001 From: davidxu Date: Tue, 12 Jan 2010 01:30:05 +0000 Subject: Update manuals of sem_open and sem_init. Submitted by: ru --- lib/libc/gen/sem_init.3 | 4 ++-- lib/libc/gen/sem_open.3 | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/sem_init.3 b/lib/libc/gen/sem_init.3 index e00cd4b..52bcb75 100644 --- a/lib/libc/gen/sem_init.3 +++ b/lib/libc/gen/sem_init.3 @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 7, 2010 +.Dd January 9, 2010 .Dt SEM_INIT 3 .Os .Sh NAME @@ -52,7 +52,7 @@ A non-zero value for specifies a shared semaphore that can be used by multiple processes, the semaphore should be located in shared memory region (see .Xr mmap 2 , -.Xr shm_open 2 , +.Xr shm_open 2 , and .Xr shmget 2 ) , any process having read and write access to address diff --git a/lib/libc/gen/sem_open.3 b/lib/libc/gen/sem_open.3 index c7ee518..3527605 100644 --- a/lib/libc/gen/sem_open.3 +++ b/lib/libc/gen/sem_open.3 @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 15, 2003 +.Dd January 9, 2010 .Dt SEM_OPEN 3 .Os .Sh NAME @@ -61,8 +61,8 @@ and This implementation places strict requirements on the value of .Fa name : it must begin with a slash -.Pq Ql / , -contain no other slash characters. +.Pq Ql / +and contain no other slash characters. .Pp The following bits may be set in the .Fa oflag -- cgit v1.1 From 197dc264ae5cd82f3d8857f7df3fc372afc9e758 Mon Sep 17 00:00:00 2001 From: brueffer Date: Tue, 12 Jan 2010 21:45:03 +0000 Subject: Miscellaneous mdoc, spelling and inconsistency fixes. PR: 142573, 142576 (mostly) Submitted by: brucec MFC after: 1 week --- lib/libc/net/sctp_bindx.3 | 2 +- lib/libc/net/sctp_connectx.3 | 6 +++--- lib/libc/net/sctp_getaddrlen.3 | 2 +- lib/libc/net/sctp_getassocid.3 | 2 +- lib/libc/net/sctp_getpaddrs.3 | 6 +++--- lib/libc/net/sctp_opt_info.3 | 4 ++-- lib/libc/net/sctp_recvmsg.3 | 19 ++++++++++--------- lib/libc/net/sctp_send.3 | 2 +- lib/libc/net/sctp_sendmsg.3 | 4 ++-- lib/libc/sys/sctp_generic_recvmsg.2 | 24 ++++++++++++++---------- lib/libc/sys/sctp_generic_sendmsg.2 | 24 ++++++++++++++---------- lib/libc/sys/sctp_peeloff.2 | 4 ++-- 12 files changed, 54 insertions(+), 45 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/net/sctp_bindx.3 b/lib/libc/net/sctp_bindx.3 index a2a2600..d047126 100644 --- a/lib/libc/net/sctp_bindx.3 +++ b/lib/libc/net/sctp_bindx.3 @@ -90,7 +90,7 @@ The call returns 0 on success and -1 upon failure. .Sh ERRORS The .Fn sctp_bindx -can return the following errors. +function can return the following errors: .Bl -tag -width Er .It Bq Er EINVAL This value is returned if the diff --git a/lib/libc/net/sctp_connectx.3 b/lib/libc/net/sctp_connectx.3 index 7b75f4a..d454bb9 100644 --- a/lib/libc/net/sctp_connectx.3 +++ b/lib/libc/net/sctp_connectx.3 @@ -44,7 +44,7 @@ .In sys/socket.h .In netinet/sctp.h .Ft int -.Fn sctp_connectx "int s" "struct sockaddr *" "int addrcnt" "sctp_assoc_t *" +.Fn sctp_connectx "int sd" "struct sockaddr *addrs" "int addrcnt" "sctp_assoc_t *id" .Sh DESCRIPTION The .Fn sctp_connectx @@ -75,7 +75,7 @@ the extra addresses sent in the call will be silently discarded from the association. On successful completion the provided -.Fa "sctp_assoc_t *" +.Fa id will be filled in with the association identification of the newly forming association. @@ -84,7 +84,7 @@ The call returns 0 on success and -1 upon failure. .Sh ERRORS The .Fn sctp_connectx -can return the following errors. +function can return the following errors: .Bl -tag -width Er .It Bq Er EINVAL An address listed has an invalid family or no diff --git a/lib/libc/net/sctp_getaddrlen.3 b/lib/libc/net/sctp_getaddrlen.3 index 325e2b0..ac7bfb3 100644 --- a/lib/libc/net/sctp_getaddrlen.3 +++ b/lib/libc/net/sctp_getaddrlen.3 @@ -76,7 +76,7 @@ system expects for the specific address family or -1. .Sh ERRORS The .Fn sctp_getaddrlen -function can return the following errors. +function can return the following errors: .Bl -tag -width Er .It Bq Er EINVAL The address family specified does NOT exist. diff --git a/lib/libc/net/sctp_getassocid.3 b/lib/libc/net/sctp_getassocid.3 index ee0926a..909b9c7 100644 --- a/lib/libc/net/sctp_getassocid.3 +++ b/lib/libc/net/sctp_getassocid.3 @@ -58,7 +58,7 @@ The call returns the association id upon success and .Sh ERRORS The .Fn sctp_getassocid -function can return the following errors. +function can return the following errors: .Bl -tag -width Er .It Bq Er ENOENT The address does not have an association setup to it. diff --git a/lib/libc/net/sctp_getpaddrs.3 b/lib/libc/net/sctp_getpaddrs.3 index 9f6d632..6ad5ea0 100644 --- a/lib/libc/net/sctp_getpaddrs.3 +++ b/lib/libc/net/sctp_getpaddrs.3 @@ -33,7 +33,7 @@ .\" $FreeBSD$ .\" .Dd December 15, 2006 -.Dt SCTP_GETPADDR 3 +.Dt SCTP_GETPADDRS 3 .Os .Sh NAME .Nm sctp_getpaddrs , @@ -64,7 +64,7 @@ array of socket addresses returned in the argument .Fa addrs upon success. .Pp -After the caller is through the function +After the caller is finished, the function .Fn sctp_freepaddrs or .Fn sctp_freeladdrs @@ -76,7 +76,7 @@ the number of addresses returned in .Fa addrs upon success. .Sh ERRORS -The functions can return the following errors. +The functions can return the following errors: .Bl -tag -width Er .It Bq Er EINVAL An address listed has an invalid family or no diff --git a/lib/libc/net/sctp_opt_info.3 b/lib/libc/net/sctp_opt_info.3 index 560b3e4..581a220 100644 --- a/lib/libc/net/sctp_opt_info.3 +++ b/lib/libc/net/sctp_opt_info.3 @@ -45,7 +45,7 @@ .In sys/socket.h .In netinet/sctp.h .Ft int -.Fn sctp_opt_info "int s" "sctp_assoc_t" "int opt" "void *arg" "socklen_t *size" +.Fn sctp_opt_info "int sd" "sctp_assoc_t id" "int opt" "void *arg" "socklen_t *size" .Sh DESCRIPTION The .Fn sctp_opt_info @@ -90,7 +90,7 @@ socket options. .Sh ERRORS The .Fn sctp_opt_info -function can return the following errors. +function can return the following errors: .Bl -tag -width Er .It Bq Er EINVAL The argument diff --git a/lib/libc/net/sctp_recvmsg.3 b/lib/libc/net/sctp_recvmsg.3 index b9ccfb8..f874880 100644 --- a/lib/libc/net/sctp_recvmsg.3 +++ b/lib/libc/net/sctp_recvmsg.3 @@ -160,7 +160,7 @@ struct sctp_sndrcvinfo { .Pp The .Fa sinfo->sinfo_ppid -is an opaque 32 bit value that is passed transparently +field is an opaque 32 bit value that is passed transparently through the stack from the peer endpoint. Note that the stack passes this value without regard to byte order. @@ -180,12 +180,13 @@ as soon as possible. When this flag is absent the message was delivered in order within the stream it was received. .Pp +The .Fa sinfo->sinfo_stream -is the SCTP stream that the message was received on. +field is the SCTP stream that the message was received on. Streams in SCTP are reliable (or partially reliable) flows of ordered messages. .Pp -The +The .Fa sinfo->sinfo_context field is used only if the local application set an association level context with the @@ -197,7 +198,7 @@ association. .Pp The .Fa sinfo->sinfo_ssn -will hold the stream sequence number assigned +field will hold the stream sequence number assigned by the peer endpoint if the message is .Em not unordered. @@ -205,7 +206,7 @@ For unordered messages this field holds an undefined value. .Pp The .Fa sinfo->sinfo_tsn -holds a transport sequence number (TSN) that was assigned +field holds a transport sequence number (TSN) that was assigned to this message by the peer endpoint. For messages that fit in or less than the path MTU this will be the only TSN assigned. @@ -215,12 +216,12 @@ message. .Pp The .Fa sinfo->sinfo_cumtsn -holds the current cumulative acknowledgment point of +field holds the current cumulative acknowledgment point of the transport association. Note that this may be larger or smaller than the TSN assigned to the message itself. .Pp -The +The .Fa sinfo->sinfo_assoc_id is the unique association identification that was assigned to the association. @@ -232,10 +233,10 @@ setting various socket options on the specific association (see .Xr sctp 4 ) . .Pp -The +The .Fa sinfo->info_timetolive field is not used by -.Fa sctp_recvmsg . +.Fn sctp_recvmsg . .Sh RETURN VALUES The call returns the number of characters sent, or -1 if an error occurred. diff --git a/lib/libc/net/sctp_send.3 b/lib/libc/net/sctp_send.3 index 2191ea1..dd96bcf 100644 --- a/lib/libc/net/sctp_send.3 +++ b/lib/libc/net/sctp_send.3 @@ -294,7 +294,7 @@ if an error occurred. The .Fn sctp_send system call -fail if: +fails if: .Bl -tag -width Er .It Bq Er EBADF An invalid descriptor was specified. diff --git a/lib/libc/net/sctp_sendmsg.3 b/lib/libc/net/sctp_sendmsg.3 index 6c48d5e..525a87c 100644 --- a/lib/libc/net/sctp_sendmsg.3 +++ b/lib/libc/net/sctp_sendmsg.3 @@ -271,7 +271,7 @@ if an error occurred. The .Fn sctp_sendmsg system call -fail if: +fails if: .Bl -tag -width Er .It Bq Er EBADF An invalid descriptor was specified. @@ -324,7 +324,7 @@ is not connected and is a one-to-one style socket. .Xr sendmsg 3 , .Xr sctp 4 .Sh BUGS -Because in the one-to-many style socket the +Because in the one-to-many style socket .Fn sctp_sendmsg or .Fn sctp_sendmsgx diff --git a/lib/libc/sys/sctp_generic_recvmsg.2 b/lib/libc/sys/sctp_generic_recvmsg.2 index ccdb9db..d6fd1b5 100644 --- a/lib/libc/sys/sctp_generic_recvmsg.2 +++ b/lib/libc/sys/sctp_generic_recvmsg.2 @@ -36,7 +36,7 @@ .Os .Sh NAME .Nm sctp_generic_recvmsg -.Nd receive data from a peer. +.Nd receive data from a peer .Sh LIBRARY .Lb libc .Sh SYNOPSIS @@ -46,16 +46,20 @@ .Ft int .Fn sctp_generic_recvmsg "int s" "struct iovec *iov" "int iovlen" "struct sockaddr *from" "socklen_t *fromlen" "struct sctp_sndrcvinfo *sinfo" "int *msgflags" .Sh DESCRIPTION -The .Fn sctp_generic_recvmsg -is the true system calls used by the -.Fn sctp_recvmsg -function call. This call is more efficient since it is a -true system calls but it is specific to FreeBSD and -can be expected NOT to be present on any other Operating -System. For detailed useage please see either the -.Fn sctp_recvmsg -function call. +is the true system call used by the +.Xr sctp_recvmsg 3 +function call. +This call is more efficient since it is a +true system call but it is specific to +.Fx +and can be expected +.Em not +to be present on any other operating +system. +For detailed usage please see the +.Xr sctp_recvmsg 3 +function call. .Sh RETURN VALUES The call returns the number of bytes read on success and -1 upon failure. .Sh ERRORS diff --git a/lib/libc/sys/sctp_generic_sendmsg.2 b/lib/libc/sys/sctp_generic_sendmsg.2 index d7050f2..fee4211 100644 --- a/lib/libc/sys/sctp_generic_sendmsg.2 +++ b/lib/libc/sys/sctp_generic_sendmsg.2 @@ -37,7 +37,7 @@ .Sh NAME .Nm sctp_generic_sendmsg .Nm sctp_generic_sendmsg_iov -.Nd send data to a peer. +.Nd send data to a peer .Sh LIBRARY .Lb libc .Sh SYNOPSIS @@ -49,21 +49,25 @@ .Ft int .Fn sctp_generic_sendmsg_iov "int s" "struct iovec *iov" "int iovlen" "struct sockaddr *to" "struct sctp_sndrcvinfo *sinfo" "int flags" .Sh DESCRIPTION -The .Fn sctp_generic_sendmsg and .Fn sctp_generic_sendmsg_iov are the true system calls used by the -.Fn sctp_sendmsg +.Xr sctp_sendmsg 3 and -.Fn sctp_send -function calls. These are more efficient since they are -true system calls but they are specific to FreeBSD and -can be expected NOT to be present on any other Operating -System. For detailed useage please see either the -.Fn sctp_send +.Xr sctp_send 3 +function calls. +These are more efficient since they are +true system calls but they are specific to +.Fx +and can be expected +.Em not +to be present on any other operating +system. +For detailed usage please see either the +.Xr sctp_send 3 or -.Fn sctp_sendmsg +.Xr sctp_sendmsg 3 function calls. .Sh RETURN VALUES The call returns the number of bytes written on success and -1 upon failure. diff --git a/lib/libc/sys/sctp_peeloff.2 b/lib/libc/sys/sctp_peeloff.2 index 0ac5be6..c513afa 100644 --- a/lib/libc/sys/sctp_peeloff.2 +++ b/lib/libc/sys/sctp_peeloff.2 @@ -36,7 +36,7 @@ .Os .Sh NAME .Nm sctp_peeloff -.Nd detach an association from a one-to-many socket to its on fd +.Nd detach an association from a one-to-many socket to its own fd .Sh LIBRARY .Lb libc .Sh SYNOPSIS @@ -58,7 +58,7 @@ upon success. .Sh ERRORS The .Fn sctp_peeloff -can return the following errors. +system call can return the following errors: .Bl -tag -width Er .It Bq Er ENOTCONN The -- cgit v1.1 From 028e43e0f75e457b7b5a88b9c7024a9c1898b990 Mon Sep 17 00:00:00 2001 From: davidxu Date: Wed, 13 Jan 2010 08:53:23 +0000 Subject: Return SEM_FAILED instead of NULL, though there are same, but the SEM_FAILED is more suitable name. In function, sem_close(), always set errno on error. --- lib/libc/gen/sem_new.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/sem_new.c b/lib/libc/gen/sem_new.c index a4bb4f3..1ec39ba 100644 --- a/lib/libc/gen/sem_new.c +++ b/lib/libc/gen/sem_new.c @@ -147,13 +147,13 @@ _sem_open(const char *name, int flags, ...) if (name[0] != '/') { errno = EINVAL; - return (NULL); + return (SEM_FAILED); } name++; if (flags & ~(O_CREAT|O_EXCL)) { errno = EINVAL; - return (NULL); + return (SEM_FAILED); } _pthread_once(&once, sem_module_init); @@ -275,6 +275,7 @@ _sem_close(sem_t *sem) return (0); } _pthread_mutex_unlock(&sem_llock); + errno = EINVAL; return (-1); } -- cgit v1.1 From ed79cccfabe6b9ba70af232bc2fb874b3062e965 Mon Sep 17 00:00:00 2001 From: ed Date: Wed, 13 Jan 2010 17:29:55 +0000 Subject: Implement . The utmpx interface is the standardized interface of the user accounting database. The standard only defines a subset of the functions that were present in System V-like systems. I'd like to highlight some of the traits my implementation has: - The standard allows the on-disk format to be different than the in-memory representation (struct utmpx). Most operating systems don't do this, but we do. This allows us to keep our ABI more stable, while giving us the opportunity to modify the on-disk format. It also allows us to use a common file format across different architectures (i.e. byte ordering). - Our implementation of pututxline() also updates wtmp and lastlog (now called utx.log and utx.lastlogin). This means the databases are more likely to be in sync. - Care must be taken that our implementation discard any fields that are not applicable. For example, our DEAD_PROCESS records do not hold a TTY name. Just a time stamp, a record identifier and a process identifier. It also guarantees that strings (ut_host, ut_line and ut_user) are null terminated. ut_id is obviously not null terminated, because it's not a string. - The API and its behaviour should be conformant to POSIX, but there may be things that slightly deviate from the standard. This implementation uses separate file descriptors when writing to the log files. It also doesn't use getutxid() to search for a field to overwrite. It uses an allocation strategy similar to getutxid(), but prevents DEAD_PROCESS records from accumulating. Make sure libulog doesn't overwrite the manpages shipped with our C library. Also keep the symbol list in Symbol.map sorted. I'll bump __FreeBSD_version later this evening. I first want to convert everything to and get rid of . --- lib/libc/gen/Makefile.inc | 12 +- lib/libc/gen/Symbol.map | 12 +- lib/libc/gen/getutxent.3 | 440 ++++++++++++++++++++++++++++++++++++++++++++++ lib/libc/gen/getutxent.c | 232 ++++++++++++++++++++++++ lib/libc/gen/pututxline.c | 277 +++++++++++++++++++++++++++++ lib/libc/gen/utxdb.c | 162 +++++++++++++++++ lib/libc/gen/utxdb.h | 61 +++++++ 7 files changed, 1190 insertions(+), 6 deletions(-) create mode 100644 lib/libc/gen/getutxent.3 create mode 100644 lib/libc/gen/getutxent.c create mode 100644 lib/libc/gen/pututxline.c create mode 100644 lib/libc/gen/utxdb.c create mode 100644 lib/libc/gen/utxdb.h (limited to 'lib/libc') diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index 2abfe57..2c0cb78 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -18,12 +18,12 @@ SRCS+= __getosreldate.c __xuname.c \ gethostname.c getloadavg.c getlogin.c getmntinfo.c getnetgrent.c \ getosreldate.c getpagesize.c getpagesizes.c \ getpeereid.c getprogname.c getpwent.c getttyent.c \ - getusershell.c getvfsbyname.c glob.c \ + getusershell.c getutxent.c getvfsbyname.c glob.c \ initgroups.c isatty.c isinf.c isnan.c jrand48.c lcong48.c \ lockf.c lrand48.c mrand48.c nftw.c nice.c \ nlist.c nrand48.c opendir.c \ pause.c pmadvise.c popen.c posix_spawn.c \ - psignal.c pw_scan.c pwcache.c \ + psignal.c pututxline.c pw_scan.c pwcache.c \ raise.c readdir.c readpassphrase.c rewinddir.c \ scandir.c seed48.c seekdir.c sem.c sem_new.c semctl.c \ setdomainname.c sethostname.c setjmperr.c setmode.c \ @@ -32,7 +32,7 @@ SRCS+= __getosreldate.c __xuname.c \ sysconf.c sysctl.c sysctlbyname.c sysctlnametomib.c \ syslog.c telldir.c termios.c time.c times.c timezone.c tls.c \ ttyname.c ttyslot.c ualarm.c ulimit.c uname.c unvis.c \ - usleep.c utime.c valloc.c vis.c wait.c wait3.c waitpid.c \ + usleep.c utime.c utxdb.c valloc.c vis.c wait.c wait3.c waitpid.c \ wordexp.c SYM_MAPS+=${.CURDIR}/gen/Symbol.map @@ -54,7 +54,7 @@ MAN+= alarm.3 arc4random.3 \ getgrent.3 getgrouplist.3 gethostname.3 getloadavg.3 \ getmntinfo.3 getnetgrent.3 getosreldate.3 getpagesize.3 \ getpagesizes.3 getpass.3 getpeereid.3 getprogname.3 getpwent.3 \ - getttyent.3 getusershell.3 getvfsbyname.3 \ + getttyent.3 getusershell.3 getutxent.3 getvfsbyname.3 \ glob.3 initgroups.3 isgreater.3 ldexp.3 lockf.3 makecontext.3 \ modf.3 \ nice.3 nlist.3 pause.3 popen.3 \ @@ -126,6 +126,10 @@ MLINKS+=getttyent.3 endttyent.3 getttyent.3 getttynam.3 \ getttyent.3 isdialuptty.3 getttyent.3 isnettty.3 \ getttyent.3 setttyent.3 MLINKS+=getusershell.3 endusershell.3 getusershell.3 setusershell.3 +MLINKS+=getutxent.3 endutxent.3 getutxent.3 getutxid.3 \ + getutxent.3 getutxline.3 getutxent.3 getutxuser.3 \ + getutxent.3 pututxline.3 getutxent.3 setutxdb.3 \ + getutxent.3 setutxent.3 MLINKS+=glob.3 globfree.3 MLINKS+=isgreater.3 isgreaterequal.3 isgreater.3 isless.3 \ isgreater.3 islessequal.3 isgreater.3 islessgreater.3 \ diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index e7d59bb..534c81a 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -359,17 +359,25 @@ FBSD_1.1 { FBSD_1.2 { basename_r; + endutxent; getpagesizes; + getutxent; + getutxid; + getutxline; + getutxuser; + pututxline; sem_close; sem_destroy; sem_getvalue; sem_init; sem_open; + sem_post; sem_timedwait; sem_trywait; - sem_post; - sem_wait; sem_unlink; + sem_wait; + setutxdb; + setutxent; }; FBSDprivate_1.0 { diff --git a/lib/libc/gen/getutxent.3 b/lib/libc/gen/getutxent.3 new file mode 100644 index 0000000..57887b1 --- /dev/null +++ b/lib/libc/gen/getutxent.3 @@ -0,0 +1,440 @@ +.\" Copyright (c) 2010 Ed Schouten +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd January 8, 2010 +.Os +.Dt GETUTXENT 3 +.Sh NAME +.Nm endutxent , +.Nm getutxent , +.Nm getutxid , +.Nm getutxline , +.Nm getutxuser , +.Nm pututxline , +.Nm setutxdb , +.Nm setutxent +.Nd user accounting database functions +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In utmpx.h +.Ft void +.Fn endutxent "void" +.Ft struct utmpx * +.Fn getutxent "void" +.Ft struct utmpx * +.Fn getutxid "const struct utmpx *id" +.Ft struct utmpx * +.Fn getutxline "const struct utmpx *line" +.Ft struct utmpx * +.Fn getutxuser "const char *user" +.Ft struct utmpx * +.Fn pututxline "const struct utmpx *utmpx" +.Ft int +.Fn setutxdb "int type" "const char *file" +.Ft void +.Fn setutxent "void" +.Sh DESCRIPTION +These functions operate on the user accounting database which stores +records of various system activities, such as user login and logouts, +but also system startups and shutdowns and modifications to the system's +clock. +The system stores these records in three databases, each having a +different purpose: +.Bl -tag -width indent +.It Pa /var/run/utx.active +Log of currently active user login sessions. +This file is similar to the traditional +.Pa utmp +file. +This file only contains process related entries, such as user login and +logout records. +.It Pa /var/log/utx.lastlogin +Log of last user login entries per user. +This file is similar to the traditional +.Pa lastlog +file. +This file only contains user login records for users who have at least +logged in once. +.It Pa /var/log/utx.log +Log of all entries, sorted by date of addition. +This file is similar to the traditional +.Pa wtmp +file. +This file may contain any type of record described below. +.El +.Pp +Each entry in these databases is defined by the structure +.Vt utmpx +found in the include file +.In utmpx.h : +.Bd -literal -offset indent +struct utmpx { + short ut_type; /* Type of entry. */ + struct timeval ut_tv; /* Time entry was made. */ + char ut_id[]; /* Record identifier. */ + pid_t ut_pid; /* Process ID. */ + char ut_user[]; /* User login name. */ + char ut_line[]; /* Device name. */ + char ut_host[]; /* Remote hostname. */ +}; +.Ed +.Pp +The +.Fa ut_type +field indicates the type of the log entry, which can have one of the +following values: +.Bl -tag -width LOGIN_PROCESS +.It Dv EMPTY +No valid user accounting information. +.It Dv BOOT_TIME +Identifies time of system boot. +.It Dv SHUTDOWN_TIME +Identifies time of system shutdown. +.It Dv OLD_TIME +Identifies time when system clock changed. +.It Dv NEW_TIME +Identifies time after system clock changed. +.It Dv USER_PROCESS +Identifies a process. +.It Dv INIT_PROCESS +Identifies a process spawned by the init process. +.It Dv LOGIN_PROCESS +Identifies the session leader of a logged-in user. +.It Dv DEAD_PROCESS +Identifies a session leader who has exited. +.El +.Pp +Entries of type +.Dv INIT_PROCESS +and +.Dv LOGIN_PROCESS +are not processed by this implementation. +.Pp +Other fields inside the structure are: +.Bl -tag -width ut_user +.It Fa ut_tv +The time the event occured. +This field is used for all types of entries. +.It Fa ut_id +An identifier that is used to refer to the entry. +This identifier can be used to remove or replace a login entry by +writing a new entry to the database containing the same value for +.Fa ut_id . +This field is only applicable to entries of type +.Dv USER_PROCESS , +.Dv INIT_PROCESS , +.Dv LOGIN_PROCESS +and +.Dv DEAD_PROCESS . +.It Fa ut_pid +The process identifier of the session leader of the login session. +This field is only applicable to entries of type +.Dv USER_PROCESS , +.Dv INIT_PROCESS , +.Dv LOGIN_PROCESS +and +.Dv DEAD_PROCESS . +.It Fa ut_user +The user login name corresponding with the login session. +This field is only applicable to entries of type +.Dv USER_PROCESS +and +.Dv INIT_PROCESS . +For +.Dv INIT_PROCESS +entries this entry typically contains the name of the login process. +.It Fa ut_line +The name of the TTY character device, without the leading +.Pa /dev/ +prefix, corresponding with the device used to facilitate the user login +session. +If no TTY character device is used, this field is left blank. +This field is only applicable to entries of type +.Dv USER_PROCESS . +.It Fa ut_host +The network hostname of the remote system, connecting to perform a user +login. +If the user login session is not performed across a network, this field +is left blank. +This field is only applicable to entries of type +.Dv USER_PROCESS . +.El +.Pp +This implementation guarantees all inapplicable fields are discarded. +The +.Fa ut_user , +.Fa ut_line +and +.Fa ut_host +fields of the structure returned by the library functions are also +guaranteed to be null-terminated in this implementation. +.Pp +The +.Fn getutxent +function can be used to read the next entry from the user accounting +database. +.Pp +The +.Fn getutxid +function searches for the next entry in the database of which the +behaviour is based on the +.Fa ut_type +field of +.Fa id . +If +.Fa ut_type +has a value of +.Dv BOOT_TIME , +.Dv SHUTDOWN_TIME , +.Dv OLD_TIME +or +.Dv NEW_TIME , +it will return the next entry whose +.Fa ut_type +has an equal value. +If +.Fa ut_type +has a value of +.Dv USER_PROCESS , +.Dv INIT_PROCESS , +.Dv LOGIN_PROCESS +or +.Dv DEAD_PROCESS , +it will return the next entry whose +.Fa ut_type +has one of the previously mentioned values and whose +.Fa ut_id +is equal. +.Pp +The +.Fn getutxline +function searches for the next entry in the database whose +.Fa ut_type +has a value of +.Dv USER_PROCESS +or +.Dv LOGIN_PROCESS +and whose +.Fa ut_line +is equal to the the same field in +.Fa line . +.Pp +The +.Fn getutxuser +function searches for the next entry in the database whose +.Fa ut_type +has a value of +.Dv USER_PROCESS +and whose +.Fa ut_user +is equal to +.Fa user . +.Pp +The previously mentioned functions will automatically try to open the +user accounting database if not already done so. +The +.Fn setutxdb +and +.Fn setutxent +functions allow the database to be opened manually, causing the offset +within the user accounting database to be rewound. +The +.Fn endutxent +function closes the database. +.Pp +The +.Fn setutxent +database always opens the active sessions database. +The +.Fn setutxdb +function opens the database identified by +.Fa type , +whose value is either +.Dv UTXDB_ACTIVE , +.Dv UTXDB_LASTLOGIN +or +.Dv UTXDB_LOG . +It will open a custom file with filename +.Fa file +instead of the system-default if +.Fa file +is not null. +Care must be taken that when using a custom filename, +.Fa type +still has to match with the actual format, since each database may use +its own file format. +.Pp +The +.Fn pututxline +function writes record +.Fa utmpx +to the system-default user accounting databases. +The value of +.Fa ut_type +determines which databases are modified. +.Pp +Entries of type +.Dv BOOT_TIME , +.Dv SHUTDOWN_TIME , +.Dv OLD_TIME +and +.Dv NEW_TIME +will only be written to +.Pa /var/log/utx.log . +.Pp +Entries of type +.Dv USER_PROCESS +will also be written to +.Pa /var/run/utx.active . +It will only be written to +.Pa /var/log/utx.lastlogin +if +.Fa ut_tv +for that user has a greater value than the existing entry or when no +entry for the user has been found. +.Pp +Entries of type +.Dv DEAD_PROCESS +will only be written to +.Pa /var/log/utx.log +and +.Pa /var/run/utx.active +if a corresponding +.Dv USER_PROCESS , +.Dv INIT_PROCESS +or +.Dv LOGIN_PROCESS +entry whose +.Fa ut_id +is equal has been found in the latter. +.Pp +In addition, entries of type +.Dv BOOT_TIME +and +.Dv SHUTDOWN_TIME +will cause all entries in +.Pa /var/run/utx.active +to be discarded. +.Pp +All entries whose type has not been mentioned previously, are discarded +by this implementation of +.Fn pututxline . +.Sh RETURN VALUES +The +.Fn getutxent , +.Fn getutxid , +.Fn getutxline , +and +.Fn getutxuser +functions return a pointer to an +.Vt utmpx +structure that matches the mentioned constraints on success or +.Dv NULL +when reaching the end-of-file or when an error occurs. +.Pp +The +.Fn pututxline +function returns a pointer to an +.Vt utmpx +structure containing a copy of the structure written to disk upon +success. +It returns +.Dv NULL +when the provided +.Vt utmpx +is invalid. +This may be because +.Fa ut_type +is invalid or +.Fa ut_type +has a value of +.Dv DEAD_PROCESS +and an entry with an identifier with a value equal to the field +.Fa ut_id +was not found. +.Pp +The +.Fn setutxdb +function returns 0 if the user accounting database was opened +successfully. +Otherwise, -1 is returned and the global variable +.Va errno +is set to indicate the error. +.Sh ERRORS +In addition to the error conditions described in +.Xr fopen 3 , +the +.Fn setutxdb +function can generate the following errors: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa type +argument contains a value not supported by this implementation. +.It Bq Er EFTYPE +The file format is invalid. +.El +.Sh SEE ALSO +.Xr last 1 , +.Xr write 1 , +.Xr getpid 2 , +.Xr gettimeofday 2 , +.Xr tty 4 , +.Xr ac 8 , +.Xr newsyslog 8 +.Sh STANDARDS +The +.Fn endutxent , +.Fn getutxent , +.Fn getutxid , +.Fn getutxline , +.Fn pututxline +and +.Fn setutxent +functions are expected to conform to +.St -p1003.1-2008 . +.Pp +The +.Fn getutxuser +and +.Fn setutxdb +functions, +the +.Fa ut_host +field of the +.Vt utmpx +structure and +.Dv SHUTDOWN_TIME +are extensions. +.Sh HISTORY +These functions appeared in +.Fx 9.0 . +They replaced the +.In utmp.h +interface. +.Sh AUTHORS +.An Ed Schouten Aq ed@FreeBSD.org diff --git a/lib/libc/gen/getutxent.c b/lib/libc/gen/getutxent.c new file mode 100644 index 0000000..13efac0 --- /dev/null +++ b/lib/libc/gen/getutxent.c @@ -0,0 +1,232 @@ +/*- + * Copyright (c) 2010 Ed Schouten + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include +#include +#include +#include +#include +#include +#include +#include "utxdb.h" +#include "un-namespace.h" + +static FILE *uf = NULL; +static int udb; +static struct utmpx utx; + +int +setutxdb(int db, const char *file) +{ + struct stat sb; + + switch (db) { + case UTXDB_ACTIVE: + if (file == NULL) + file = _PATH_UTX_ACTIVE; + break; + case UTXDB_LASTLOGIN: + if (file == NULL) + file = _PATH_UTX_LASTLOGIN; + break; + case UTXDB_LOG: + if (file == NULL) + file = _PATH_UTX_LOG; + break; + default: + errno = EINVAL; + return (-1); + } + + if (uf != NULL) + fclose(uf); + uf = fopen(file, "r"); + if (uf == NULL) + return (-1); + + /* Safety check: never use broken files. */ + if (db != UTXDB_LOG && _fstat(fileno(uf), &sb) != -1 && + sb.st_size % sizeof(struct futx) != 0) { + fclose(uf); + uf = NULL; + errno = EFTYPE; + return (-1); + } + + udb = db; + return (0); +} + +void +setutxent(void) +{ + + setutxdb(UTXDB_ACTIVE, NULL); +} + +void +endutxent(void) +{ + + if (uf != NULL) { + fclose(uf); + uf = NULL; + } +} + +static struct futx * +getfutxent(void) +{ + static struct futx fu; + + if (uf == NULL) + setutxent(); + if (uf == NULL) + return (NULL); + + if (udb == UTXDB_LOG) { + uint16_t len; + + if (fread(&len, sizeof len, 1, uf) != 1) + return (NULL); + len = be16toh(len); + if (len > sizeof fu) { + /* Forward compatibility. */ + if (fread(&fu, sizeof fu, 1, uf) != 1) + return (NULL); + fseek(uf, len - sizeof fu, SEEK_CUR); + } else { + /* Partial record. */ + memset(&fu, 0, sizeof fu); + if (fread(&fu, len, 1, uf) != 1) + return (NULL); + } + } else { + if (fread(&fu, sizeof fu, 1, uf) != 1) + return (NULL); + } + return (&fu); +} + +struct utmpx * +getutxent(void) +{ + struct futx *fu; + + fu = getfutxent(); + if (fu == NULL) + return (NULL); + futx_to_utx(fu, &utx); + return (&utx); +} + +struct utmpx * +getutxid(const struct utmpx *id) +{ + struct futx *fu; + + for (;;) { + fu = getfutxent(); + if (fu == NULL) + return (NULL); + + switch (fu->fu_type) { + case BOOT_TIME: + case OLD_TIME: + case NEW_TIME: + case SHUTDOWN_TIME: + if (fu->fu_type == id->ut_type) + goto found; + case USER_PROCESS: + case INIT_PROCESS: + case LOGIN_PROCESS: + case DEAD_PROCESS: + switch (id->ut_type) { + case USER_PROCESS: + case INIT_PROCESS: + case LOGIN_PROCESS: + case DEAD_PROCESS: + if (memcmp(fu->fu_id, id->ut_id, + MIN(sizeof fu->fu_id, sizeof id->ut_id)) == 0) + goto found; + } + } + } + +found: + futx_to_utx(fu, &utx); + return (&utx); +} + +struct utmpx * +getutxline(const struct utmpx *line) +{ + struct futx *fu; + + for (;;) { + fu = getfutxent(); + if (fu == NULL) + return (NULL); + + switch (fu->fu_type) { + case USER_PROCESS: + case LOGIN_PROCESS: + if (strncmp(fu->fu_line, line->ut_line, + MIN(sizeof fu->fu_line, sizeof line->ut_line)) == 0) + goto found; + } + } + +found: + futx_to_utx(fu, &utx); + return (&utx); +} + +struct utmpx * +getutxuser(const char *user) +{ + struct futx *fu; + + for (;;) { + fu = getfutxent(); + if (fu == NULL) + return (NULL); + + switch (fu->fu_type) { + case USER_PROCESS: + if (strncmp(fu->fu_user, user, sizeof fu->fu_user) == 0) + goto found; + } + } + +found: + futx_to_utx(fu, &utx); + return (&utx); +} diff --git a/lib/libc/gen/pututxline.c b/lib/libc/gen/pututxline.c new file mode 100644 index 0000000..8c2e91d --- /dev/null +++ b/lib/libc/gen/pututxline.c @@ -0,0 +1,277 @@ +/*- + * Copyright (c) 2010 Ed Schouten + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "utxdb.h" +#include "un-namespace.h" + +static FILE * +futx_open(const char *file) +{ + int fd; + FILE *fp; + struct stat sb; + + fd = _open(file, O_CREAT|O_RDWR|O_EXLOCK, 0644); + if (fd < 0) + return (NULL); + + /* Safety check: never use broken files. */ + if (_fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0) { + _close(fd); + return (NULL); + } + + fp = fdopen(fd, "r+"); + if (fp == NULL) { + _close(fd); + return (NULL); + } + + return (fp); +} + +static void +utx_active_add(const struct futx *fu) +{ + FILE *fp; + struct futx fe; + off_t partial = -1; + + /* + * Register user login sessions. Overwrite entries of sessions + * that have already been terminated. + */ + fp = futx_open(_PATH_UTX_ACTIVE); + if (fp == NULL) + return; + while (fread(&fe, sizeof fe, 1, fp) == 1) { + switch (fe.fu_type) { + case USER_PROCESS: + case INIT_PROCESS: + case LOGIN_PROCESS: + case DEAD_PROCESS: + /* Overwrite when ut_id matches. */ + if (memcmp(fu->fu_id, fe.fu_id, sizeof fe.fu_id) == 0) { + fseeko(fp, -sizeof fe, SEEK_CUR); + goto exact; + } + if (fe.fu_type != DEAD_PROCESS) + break; + /* FALLTHROUGH */ + default: + /* Allow us to overwrite unused records. */ + if (partial == -1) + partial = fseeko(fp, 0, SEEK_CUR) - sizeof fe; + break; + } + } + + /* + * No exact match found. Use the partial match. If no partial + * match was found, just append a new record. + */ + if (partial != -1) + fseeko(fp, partial, SEEK_SET); +exact: + fwrite(fu, sizeof *fu, 1, fp); + fclose(fp); +} + +static int +utx_active_remove(struct futx *fu) +{ + FILE *fp; + struct futx fe; + + /* + * Remove user login sessions, having the same ut_id. + */ + fp = futx_open(_PATH_UTX_ACTIVE); + if (fp == NULL) + return (0); + while (fread(&fe, sizeof fe, 1, fp) == 1) { + switch (fe.fu_type) { + case USER_PROCESS: + case INIT_PROCESS: + case LOGIN_PROCESS: + if (memcmp(fu->fu_id, fe.fu_id, sizeof fe.fu_id) != 0) + continue; + + /* + * Prevent login sessions from having a negative + * timespan. + */ + if (be64toh(fu->fu_tv) < be64toh(fe.fu_tv)) + fu->fu_tv = fe.fu_tv; + + /* Terminate session. */ + fseeko(fp, -sizeof fe, SEEK_CUR); + fwrite(fu, sizeof *fu, 1, fp); + fclose(fp); + return (0); + } + } + + fclose(fp); + return (1); +} + +static void +utx_active_purge(void) +{ + + truncate(_PATH_UTX_ACTIVE, 0); +} + +static void +utx_lastlogin_add(const struct futx *fu) +{ + FILE *fp; + struct futx fe; + + /* + * Write an entry to lastlogin. Overwrite the entry if the + * current user already has an entry. If not, append a new + * entry. + */ + fp = futx_open(_PATH_UTX_LASTLOGIN); + if (fp == NULL) + return; + while (fread(&fe, sizeof fe, 1, fp) == 1) { + if (strncmp(fu->fu_user, fe.fu_user, sizeof fe.fu_user) != 0) + continue; + + /* Prevent lowering the time value. */ + if (be64toh(fu->fu_tv) <= be64toh(fe.fu_tv)) + goto done; + + /* Found a previous lastlogin entry for this user. */ + fseeko(fp, -sizeof fe, SEEK_CUR); + break; + } + fwrite(fu, sizeof *fu, 1, fp); +done: + fclose(fp); +} + +static void +utx_lastlogin_upgrade(void) +{ + int fd; + struct stat sb; + + fd = _open(_PATH_UTX_LASTLOGIN, O_RDWR, 0644); + if (fd < 0) + return; + + /* + * Truncate broken lastlogin files. In the future we should + * check for older versions of the file format here and try to + * upgrade it. + */ + if (_fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0) + ftruncate(fd, 0); + _close(fd); +} + +static void +utx_log_add(const struct futx *fu) +{ + int fd; + uint16_t l; + struct iovec vec[2]; + + /* + * Append an entry to the log file. We only need to append + * records to this file, so to conserve space, trim any trailing + * zero-bytes. Prepend a length field, indicating the length of + * the record, excluding the length field itself. + */ + for (l = sizeof *fu; l > 0 && ((const char *)fu)[l - 1] == '\0'; l--); + vec[0].iov_base = &l; + vec[0].iov_len = sizeof l; + vec[1].iov_base = __DECONST(void *, fu); + vec[1].iov_len = l; + l = htobe16(l); + + fd = _open(_PATH_UTX_LOG, O_CREAT|O_WRONLY|O_APPEND, 0644); + if (fd < 0) + return; + _writev(fd, vec, 2); + _close(fd); +} + +struct utmpx * +pututxline(const struct utmpx *utmpx) +{ + struct futx fu; + static struct utmpx ut; + + utx_to_futx(utmpx, &fu); + + switch (fu.fu_type) { + case BOOT_TIME: + case SHUTDOWN_TIME: + utx_active_purge(); + utx_lastlogin_upgrade(); + break; + case OLD_TIME: + case NEW_TIME: + break; + case USER_PROCESS: + utx_active_add(&fu); + utx_lastlogin_add(&fu); + break; +#if 0 /* XXX: Are these records of any use to us? */ + case INIT_PROCESS: + case LOGIN_PROCESS: + utx_active_add(&fu); + break; +#endif + case DEAD_PROCESS: + if (utx_active_remove(&fu) != 0) + return (NULL); + break; + default: + return (NULL); + } + + utx_log_add(&fu); + futx_to_utx(&fu, &ut); + return (&ut); +} diff --git a/lib/libc/gen/utxdb.c b/lib/libc/gen/utxdb.c new file mode 100644 index 0000000..d7e2b34 --- /dev/null +++ b/lib/libc/gen/utxdb.c @@ -0,0 +1,162 @@ +/*- + * Copyright (c) 2010 Ed Schouten + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include +#include +#include +#include +#include "utxdb.h" +#include "un-namespace.h" + +#define UTOF_STRING(ut, fu, field) do { \ + strncpy((fu)->fu_ ## field, (ut)->ut_ ## field, \ + MIN(sizeof (fu)->fu_ ## field, sizeof (ut)->ut_ ## field)); \ +} while (0) +#define UTOF_ID(ut, fu) do { \ + memcpy((fu)->fu_id, (ut)->ut_id, \ + MIN(sizeof (fu)->fu_id, sizeof (ut)->ut_id)); \ +} while (0) +#define UTOF_PID(ut, fu) do { \ + (fu)->fu_pid = htobe32((ut)->ut_pid); \ +} while (0) +#define UTOF_TYPE(ut, fu) do { \ + (fu)->fu_type = (ut)->ut_type; \ +} while (0) +#define UTOF_TV(ut, fu) do { \ + (fu)->fu_tv = htobe64((uint64_t)(ut)->ut_tv.tv_sec * 1000000 + \ + (uint64_t)(ut)->ut_tv.tv_usec); \ +} while (0) + +void +utx_to_futx(const struct utmpx *ut, struct futx *fu) +{ + + memset(fu, 0, sizeof *fu); + + switch (ut->ut_type) { + case BOOT_TIME: + case OLD_TIME: + case NEW_TIME: + /* Extension: shutdown time. */ + case SHUTDOWN_TIME: + break; + case USER_PROCESS: + UTOF_ID(ut, fu); + UTOF_STRING(ut, fu, user); + UTOF_STRING(ut, fu, line); + /* Extension: host name. */ + UTOF_STRING(ut, fu, host); + UTOF_PID(ut, fu); + break; + case INIT_PROCESS: + UTOF_ID(ut, fu); + UTOF_PID(ut, fu); + break; + case LOGIN_PROCESS: + UTOF_ID(ut, fu); + UTOF_STRING(ut, fu, user); + UTOF_PID(ut, fu); + break; + case DEAD_PROCESS: + UTOF_ID(ut, fu); + UTOF_PID(ut, fu); + break; + default: + fu->fu_type = EMPTY; + return; + } + + UTOF_TYPE(ut, fu); + UTOF_TV(ut, fu); +} + +#define FTOU_STRING(fu, ut, field) do { \ + strncpy((ut)->ut_ ## field, (fu)->fu_ ## field, \ + MIN(sizeof (ut)->ut_ ## field - 1, sizeof (fu)->fu_ ## field)); \ +} while (0) +#define FTOU_ID(fu, ut) do { \ + memcpy((ut)->ut_id, (fu)->fu_id, \ + MIN(sizeof (ut)->ut_id, sizeof (fu)->fu_id)); \ +} while (0) +#define FTOU_PID(fu, ut) do { \ + (ut)->ut_pid = be32toh((fu)->fu_pid); \ +} while (0) +#define FTOU_TYPE(fu, ut) do { \ + (ut)->ut_type = (fu)->fu_type; \ +} while (0) +#define FTOU_TV(fu, ut) do { \ + uint64_t t; \ + t = be64toh((fu)->fu_tv); \ + (ut)->ut_tv.tv_sec = t / 1000000; \ + (ut)->ut_tv.tv_usec = t % 1000000; \ +} while (0) + +void +futx_to_utx(const struct futx *fu, struct utmpx *ut) +{ + + memset(ut, 0, sizeof *ut); + + switch (fu->fu_type) { + case BOOT_TIME: + case OLD_TIME: + case NEW_TIME: + /* Extension: shutdown time. */ + case SHUTDOWN_TIME: + break; + case USER_PROCESS: + FTOU_ID(fu, ut); + FTOU_STRING(fu, ut, user); + FTOU_STRING(fu, ut, line); + /* Extension: host name. */ + FTOU_STRING(fu, ut, host); + FTOU_PID(fu, ut); + break; + case INIT_PROCESS: + FTOU_ID(fu, ut); + FTOU_PID(fu, ut); + break; + case LOGIN_PROCESS: + FTOU_ID(fu, ut); + FTOU_STRING(fu, ut, user); + FTOU_PID(fu, ut); + break; + case DEAD_PROCESS: + FTOU_ID(fu, ut); + FTOU_PID(fu, ut); + break; + default: + ut->ut_type = EMPTY; + return; + } + + FTOU_TYPE(fu, ut); + FTOU_TV(fu, ut); +} diff --git a/lib/libc/gen/utxdb.h b/lib/libc/gen/utxdb.h new file mode 100644 index 0000000..ec02013 --- /dev/null +++ b/lib/libc/gen/utxdb.h @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 2010 Ed Schouten + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _UTXDB_H_ +#define _UTXDB_H_ + +#include + +#define _PATH_UTX_ACTIVE "/var/run/utx.active" +#define _PATH_UTX_LASTLOGIN "/var/log/utx.lastlogin" +#define _PATH_UTX_LOG "/var/log/utx.log" + +/* + * Entries in struct futx are ordered by how often they are used. In + * utx.log only entries will be written until the last non-zero byte, + * which means we want to put the hostname at the end. Most primitive + * records only store a ut_type and ut_tv, which means we want to store + * those at the front. + */ + +struct utmpx; + +struct futx { + uint8_t fu_type; + uint64_t fu_tv; + char fu_id[8]; + uint32_t fu_pid; + char fu_user[32]; + char fu_line[16]; + char fu_host[128]; +} __packed; + +void utx_to_futx(const struct utmpx *, struct futx *); +void futx_to_utx(const struct futx *, struct utmpx *); + +#endif /* !_UTXDB_H_ */ -- cgit v1.1 From c47f4ccef36eabbc9ea7c65e2a8e9b2e9814d08a Mon Sep 17 00:00:00 2001 From: ed Date: Thu, 14 Jan 2010 05:35:32 +0000 Subject: Phase out ttyslot(3). The ttyslot() function was originally part for SUSv1, marked LEGACY in SUSv2 and removed later on. This function only makes sense when using utmp(5), because it was used to determine the offset of the record for the controlling TTY. It makes little sense to keep it here, because the new utmpx file format doesn't index based on TTY slots. --- lib/libc/gen/Symbol.map | 1 - lib/libc/gen/ttyname.3 | 23 +++-------------------- lib/libc/gen/ttyslot.c | 4 +++- 3 files changed, 6 insertions(+), 22 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index 534c81a..42404bc 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -272,7 +272,6 @@ FBSD_1.0 { openlog; closelog; setlogmask; - ttyslot; ttyname_r; ttyname; timezone; diff --git a/lib/libc/gen/ttyname.3 b/lib/libc/gen/ttyname.3 index c7b8cbc..e583833 100644 --- a/lib/libc/gen/ttyname.3 +++ b/lib/libc/gen/ttyname.3 @@ -34,8 +34,7 @@ .Sh NAME .Nm ttyname , .Nm ttyname_r , -.Nm isatty , -.Nm ttyslot +.Nm isatty .Nd get name of associated terminal (tty) from file descriptor .Sh LIBRARY .Lb libc @@ -47,8 +46,6 @@ .Fn ttyname_r "int fd" "char *buf" "size_t len" .Ft int .Fn isatty "int fd" -.Ft int -.Fn ttyslot void .Sh DESCRIPTION These functions operate on the system file descriptors for terminal type devices. @@ -89,13 +86,6 @@ The .Fn ttyname_r function takes a buffer and length as arguments to avoid this problem. -.Pp -The -.Fn ttyslot -function -fetches the current process' control terminal number from the -.Xr ttys 5 -file entry. .Sh RETURN VALUES The .Fn ttyname @@ -110,12 +100,6 @@ The .Fn ttyname_r function returns 0 if successful. Otherwise an error number is returned. -.Pp -The -.Fn ttyslot -function -returns the unit number of the device file if found; otherwise -the value zero is returned. .Sh FILES .Bl -tag -width ".Pa /etc/ttys" -compact .It Pa /dev/\(** @@ -142,10 +126,9 @@ is smaller than the length of the string to be returned. .Xr ttys 5 .Sh HISTORY The -.Fn isatty , -.Fn ttyname , +.Fn isatty and -.Fn ttyslot +.Fn ttyname functions appeared in .At v7 . diff --git a/lib/libc/gen/ttyslot.c b/lib/libc/gen/ttyslot.c index 31cc156..b2fac7c 100644 --- a/lib/libc/gen/ttyslot.c +++ b/lib/libc/gen/ttyslot.c @@ -40,7 +40,7 @@ __FBSDID("$FreeBSD$"); #include int -ttyslot() +__ttyslot(void) { struct ttyent *ttyp; int slot; @@ -63,3 +63,5 @@ ttyslot() endttyent(); return(0); } + +__sym_compat(ttyslot, __ttyslot, FBSD_1.0); -- cgit v1.1 From 2bf206e0010131bb276c0d1c657a8081f2c17359 Mon Sep 17 00:00:00 2001 From: ed Date: Thu, 14 Jan 2010 05:37:43 +0000 Subject: Add two changes that should have gone into commit r202274. Phase out ttyslot(3). The ttyslot() function was originally part for SUSv1, marked LEGACY in SUSv2 and removed later on. This function only makes sense when using utmp(5), because it was used to determine the offset of the record for the controlling TTY. It makes little sense to keep it here, because the new utmpx file format doesn't index based on TTY slots. --- lib/libc/gen/Makefile.inc | 2 +- lib/libc/gen/getttyent.3 | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index 2c0cb78..2f562da 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -177,7 +177,7 @@ MLINKS+=tcsetattr.3 cfgetispeed.3 tcsetattr.3 cfgetospeed.3 \ tcsetattr.3 cfmakeraw.3 tcsetattr.3 cfsetispeed.3 \ tcsetattr.3 cfsetospeed.3 tcsetattr.3 cfsetspeed.3 \ tcsetattr.3 tcgetattr.3 -MLINKS+=ttyname.3 isatty.3 ttyname.3 ttyname_r.3 ttyname.3 ttyslot.3 +MLINKS+=ttyname.3 isatty.3 ttyname.3 ttyname_r.3 MLINKS+=tzset.3 tzsetwall.3 MLINKS+=unvis.3 strunvis.3 unvis.3 strunvisx.3 MLINKS+=vis.3 strvis.3 vis.3 strvisx.3 diff --git a/lib/libc/gen/getttyent.3 b/lib/libc/gen/getttyent.3 index 0be7991..18c3f07 100644 --- a/lib/libc/gen/getttyent.3 +++ b/lib/libc/gen/getttyent.3 @@ -188,7 +188,6 @@ zero otherwise. .El .Sh SEE ALSO .Xr login 1 , -.Xr ttyslot 3 , .Xr gettytab 5 , .Xr termcap 5 , .Xr ttys 5 , -- cgit v1.1 From 61e4e14b1517ccbcfd599caa75d074f7e0d9410c Mon Sep 17 00:00:00 2001 From: ed Date: Thu, 14 Jan 2010 08:08:55 +0000 Subject: Don't use fseeko() to obtain the file offset. I was a bit confused with lseek(), which returns the new offset. We should ftello() to obtain it using stdio. --- lib/libc/gen/pututxline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/pututxline.c b/lib/libc/gen/pututxline.c index 8c2e91d..c0440df 100644 --- a/lib/libc/gen/pututxline.c +++ b/lib/libc/gen/pututxline.c @@ -96,7 +96,7 @@ utx_active_add(const struct futx *fu) default: /* Allow us to overwrite unused records. */ if (partial == -1) - partial = fseeko(fp, 0, SEEK_CUR) - sizeof fe; + partial = ftello(fp) - sizeof fe; break; } } -- cgit v1.1 From c310e1750a01a0d25146954cd56d233d3c9648dc Mon Sep 17 00:00:00 2001 From: ed Date: Thu, 14 Jan 2010 10:00:01 +0000 Subject: Revert the change to Symbol.map, made in r202274. Even though we use __sym_compat(), we should list the symbol in Symbol.map. ttyslot() is now listed as follows, which seems to do the right thing: | Symbol table '.dynsym' contains 2755 entries: | Num: Value Size Type Bind Vis Ndx Name | 613: 00000000000477b0 121 FUNC GLOBAL DEFAULT 10 ttyslot@FBSD_1.0 Reported by: kib --- lib/libc/gen/Symbol.map | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/libc') diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index 42404bc..534c81a 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -272,6 +272,7 @@ FBSD_1.0 { openlog; closelog; setlogmask; + ttyslot; ttyname_r; ttyname; timezone; -- cgit v1.1 From 64aac684586e30062e84858aef4672ac29360039 Mon Sep 17 00:00:00 2001 From: ed Date: Thu, 14 Jan 2010 15:20:09 +0000 Subject: Unbreak pututxline() on 32-bit architectures. I forgot to cast the size_t's back to off_t before negating them, causing all sorts of artifacts where the log files would grow to 2^32 - 197 bytes. Reported by: ume --- lib/libc/gen/pututxline.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/pututxline.c b/lib/libc/gen/pututxline.c index c0440df..94c63bd 100644 --- a/lib/libc/gen/pututxline.c +++ b/lib/libc/gen/pututxline.c @@ -87,7 +87,7 @@ utx_active_add(const struct futx *fu) case DEAD_PROCESS: /* Overwrite when ut_id matches. */ if (memcmp(fu->fu_id, fe.fu_id, sizeof fe.fu_id) == 0) { - fseeko(fp, -sizeof fe, SEEK_CUR); + fseeko(fp, -(off_t)sizeof fe, SEEK_CUR); goto exact; } if (fe.fu_type != DEAD_PROCESS) @@ -96,7 +96,7 @@ utx_active_add(const struct futx *fu) default: /* Allow us to overwrite unused records. */ if (partial == -1) - partial = ftello(fp) - sizeof fe; + partial = ftello(fp) - (off_t)sizeof fe; break; } } @@ -140,7 +140,7 @@ utx_active_remove(struct futx *fu) fu->fu_tv = fe.fu_tv; /* Terminate session. */ - fseeko(fp, -sizeof fe, SEEK_CUR); + fseeko(fp, -(off_t)sizeof fe, SEEK_CUR); fwrite(fu, sizeof *fu, 1, fp); fclose(fp); return (0); @@ -181,7 +181,7 @@ utx_lastlogin_add(const struct futx *fu) goto done; /* Found a previous lastlogin entry for this user. */ - fseeko(fp, -sizeof fe, SEEK_CUR); + fseeko(fp, -(off_t)sizeof fe, SEEK_CUR); break; } fwrite(fu, sizeof *fu, 1, fp); -- cgit v1.1 From 922d9eeb784ff7f37e6c8a3cc33930502fd9e2ae Mon Sep 17 00:00:00 2001 From: ed Date: Thu, 14 Jan 2010 15:20:46 +0000 Subject: Remove ttyslot from Symbol.map anyway. Requested by: kan --- lib/libc/gen/Symbol.map | 1 - 1 file changed, 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index 534c81a..42404bc 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -272,7 +272,6 @@ FBSD_1.0 { openlog; closelog; setlogmask; - ttyslot; ttyname_r; ttyname; timezone; -- cgit v1.1 From d3ac61ad014895ceb49c76a8fa961a08f7983079 Mon Sep 17 00:00:00 2001 From: ed Date: Thu, 14 Jan 2010 20:58:45 +0000 Subject: Add wtmpcvt(1). This utility allows users to convert their wtmp databases to the new format. It makes no sense for users to keep their wtmp log files if they are unable to view them. It basically copies ut_line into ut_id as well. This makes it possible for last(1) and ac(8) to match login records with their corresponding logout record. --- lib/libc/gen/getutxent.3 | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/libc') diff --git a/lib/libc/gen/getutxent.3 b/lib/libc/gen/getutxent.3 index 57887b1..c37240e 100644 --- a/lib/libc/gen/getutxent.3 +++ b/lib/libc/gen/getutxent.3 @@ -401,6 +401,7 @@ The file format is invalid. .Sh SEE ALSO .Xr last 1 , .Xr write 1 , +.Xr wtmpcvt 1 , .Xr getpid 2 , .Xr gettimeofday 2 , .Xr tty 4 , -- cgit v1.1 From 2bffa8c7ba63face9a0759d932b37a9a92fa70e1 Mon Sep 17 00:00:00 2001 From: davidxu Date: Fri, 15 Jan 2010 01:19:58 +0000 Subject: Also call sem_module_init in sem_close to initialize mutex with some attributes. --- lib/libc/gen/sem_new.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/gen/sem_new.c b/lib/libc/gen/sem_new.c index 1ec39ba..f513973 100644 --- a/lib/libc/gen/sem_new.c +++ b/lib/libc/gen/sem_new.c @@ -255,6 +255,8 @@ _sem_close(sem_t *sem) return (-1); } + _pthread_once(&once, sem_module_init); + _pthread_mutex_lock(&sem_llock); LIST_FOREACH(ni, &sem_list, next) { if (sem == ni->sem) { -- cgit v1.1 From 659d6713f842504f574711d0f89218e557b49e15 Mon Sep 17 00:00:00 2001 From: ed Date: Sat, 16 Jan 2010 17:05:27 +0000 Subject: Unexpose the old uname(3) function. Nowadays uname(3) is an inline function around __xuname(3). Prevent linkage of new binaries against this compatibility function, similar to what I did with ttyslot(3). --- lib/libc/gen/Symbol.map | 1 - lib/libc/gen/uname.c | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index 42404bc..c21e936 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -296,7 +296,6 @@ FBSD_1.0 { tcflow; ualarm; ulimit; - uname; unvis; strunvis; strunvisx; diff --git a/lib/libc/gen/uname.c b/lib/libc/gen/uname.c index 5a7baf7..5f8422a 100644 --- a/lib/libc/gen/uname.c +++ b/lib/libc/gen/uname.c @@ -33,15 +33,15 @@ static char sccsid[] = "From: @(#)uname.c 8.1 (Berkeley) 1/4/94"; #include __FBSDID("$FreeBSD$"); -#define uname wrapped_uname #include #include #include #include -#undef uname int -uname(struct utsname *name) +__uname(struct utsname *name) { return __xuname(32, name); } + +__sym_compat(uname, __uname, FBSD_1.0); -- cgit v1.1 From 47ae443fa5f3b739136606b138c2a4bc9b904974 Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 17 Jan 2010 15:43:14 +0000 Subject: Simplify ttyslot(3). After comparing how other systems deal with utmp/utmpx, I noticed many systems don't even care about ttyslot(3) anymore, since utmpx doesn't use TTY slots anyway. We don't provide any tools to access old utmp files anymore, so there is no use in letting applications write to a proper offset within the utmp file. Just let ttyslot(3) always return 0, which seems to be the default behaviour on operating systems like Linux as well. --- lib/libc/gen/ttyslot.c | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/ttyslot.c b/lib/libc/gen/ttyslot.c index b2fac7c..1de0837 100644 --- a/lib/libc/gen/ttyslot.c +++ b/lib/libc/gen/ttyslot.c @@ -33,35 +33,11 @@ static char sccsid[] = "@(#)ttyslot.c 8.1 (Berkeley) 6/4/93"; #include __FBSDID("$FreeBSD$"); -#include -#include -#include -#include -#include - int __ttyslot(void) { - struct ttyent *ttyp; - int slot; - int cnt; - char *name; - setttyent(); - for (cnt = 0; cnt < 3; ++cnt) - if ( (name = ttyname(cnt)) ) { - if (strncmp(name, _PATH_DEV, sizeof _PATH_DEV - 1) != 0) - break; - name += sizeof _PATH_DEV - 1; - for (slot = 1; (ttyp = getttyent()); ++slot) - if (!strcmp(ttyp->ty_name, name)) { - endttyent(); - return(slot); - } - break; - } - endttyent(); - return(0); + return (0); } __sym_compat(ttyslot, __ttyslot, FBSD_1.0); -- cgit v1.1 From c3852c9e0e86dccecc5163b3ea19764f1afcf5cb Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 17 Jan 2010 21:00:29 +0000 Subject: Add forgotten break; keyword to getutxid(). We should not fall through to the ut_id comparison. Only ut_type should be compared when using OLD_TIME, NEW_TIME, BOOT_TIME or SHUTDOWN_TIME. --- lib/libc/gen/getutxent.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/gen/getutxent.c b/lib/libc/gen/getutxent.c index 13efac0..08b120bae 100644 --- a/lib/libc/gen/getutxent.c +++ b/lib/libc/gen/getutxent.c @@ -164,6 +164,7 @@ getutxid(const struct utmpx *id) case SHUTDOWN_TIME: if (fu->fu_type == id->ut_type) goto found; + break; case USER_PROCESS: case INIT_PROCESS: case LOGIN_PROCESS: @@ -177,6 +178,7 @@ getutxid(const struct utmpx *id) MIN(sizeof fu->fu_id, sizeof id->ut_id)) == 0) goto found; } + break; } } -- cgit v1.1 From f9a77ba26579e3f9f2b0eec8ffe1f24442e5a59a Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 17 Jan 2010 21:40:05 +0000 Subject: Perform several small cleanups to the utmpx code. - Massively reduce BSS usage. Let futx_to_utx() dynamically allocate the structure. There is only a very small amount of applications out there that needs to use the utmpx database. Wasting 1 KB on unused structures makes little sense. - Just let getutxid() search for matching ut_id's for any *PROCESS-type. This makes the code a bit more future-proof. - Fix a POSIX-mistake: when reading POSIX and the OpenSolaris implementation, getutxline() must return USER_PROCESS and LOGIN_PROCESS records whose ut_lines match. When reading POSIX, it seems LOGIN_PROCESS should not use ut_line at the first place. I have reported this issue. --- lib/libc/gen/getutxent.3 | 4 ++- lib/libc/gen/getutxent.c | 91 +++++++++++++++++++++-------------------------- lib/libc/gen/pututxline.c | 4 +-- lib/libc/gen/utxdb.c | 21 ++++++++--- lib/libc/gen/utxdb.h | 2 +- 5 files changed, 62 insertions(+), 60 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/getutxent.3 b/lib/libc/gen/getutxent.3 index c37240e..58b1280 100644 --- a/lib/libc/gen/getutxent.3 +++ b/lib/libc/gen/getutxent.3 @@ -174,7 +174,9 @@ prefix, corresponding with the device used to facilitate the user login session. If no TTY character device is used, this field is left blank. This field is only applicable to entries of type -.Dv USER_PROCESS . +.Dv USER_PROCESS +and +.Dv LOGIN_PROCESS . .It Fa ut_host The network hostname of the remote system, connecting to perform a user login. diff --git a/lib/libc/gen/getutxent.c b/lib/libc/gen/getutxent.c index 08b120bae..654a634 100644 --- a/lib/libc/gen/getutxent.c +++ b/lib/libc/gen/getutxent.c @@ -40,7 +40,6 @@ __FBSDID("$FreeBSD$"); static FILE *uf = NULL; static int udb; -static struct utmpx utx; int setutxdb(int db, const char *file) @@ -101,70 +100,59 @@ endutxent(void) } } -static struct futx * -getfutxent(void) +static int +getfutxent(struct futx *fu) { - static struct futx fu; if (uf == NULL) setutxent(); if (uf == NULL) - return (NULL); + return (-1); if (udb == UTXDB_LOG) { uint16_t len; if (fread(&len, sizeof len, 1, uf) != 1) - return (NULL); + return (-1); len = be16toh(len); - if (len > sizeof fu) { + if (len > sizeof *fu) { /* Forward compatibility. */ - if (fread(&fu, sizeof fu, 1, uf) != 1) - return (NULL); - fseek(uf, len - sizeof fu, SEEK_CUR); + if (fread(fu, sizeof *fu, 1, uf) != 1) + return (-1); + fseek(uf, len - sizeof *fu, SEEK_CUR); } else { /* Partial record. */ - memset(&fu, 0, sizeof fu); - if (fread(&fu, len, 1, uf) != 1) - return (NULL); + memset(fu, 0, sizeof *fu); + if (fread(fu, len, 1, uf) != 1) + return (-1); } } else { - if (fread(&fu, sizeof fu, 1, uf) != 1) - return (NULL); + if (fread(fu, sizeof *fu, 1, uf) != 1) + return (-1); } - return (&fu); + return (0); } struct utmpx * getutxent(void) { - struct futx *fu; + struct futx fu; - fu = getfutxent(); - if (fu == NULL) + if (getfutxent(&fu) != 0) return (NULL); - futx_to_utx(fu, &utx); - return (&utx); + return (futx_to_utx(&fu)); } struct utmpx * getutxid(const struct utmpx *id) { - struct futx *fu; + struct futx fu; for (;;) { - fu = getfutxent(); - if (fu == NULL) + if (getfutxent(&fu) != 0) return (NULL); - switch (fu->fu_type) { - case BOOT_TIME: - case OLD_TIME: - case NEW_TIME: - case SHUTDOWN_TIME: - if (fu->fu_type == id->ut_type) - goto found; - break; + switch (fu.fu_type) { case USER_PROCESS: case INIT_PROCESS: case LOGIN_PROCESS: @@ -174,61 +162,62 @@ getutxid(const struct utmpx *id) case INIT_PROCESS: case LOGIN_PROCESS: case DEAD_PROCESS: - if (memcmp(fu->fu_id, id->ut_id, - MIN(sizeof fu->fu_id, sizeof id->ut_id)) == 0) + if (memcmp(fu.fu_id, id->ut_id, + MIN(sizeof fu.fu_id, sizeof id->ut_id)) == 0) goto found; } break; + default: + if (fu.fu_type == id->ut_type) + goto found; + break; } } found: - futx_to_utx(fu, &utx); - return (&utx); + return (futx_to_utx(&fu)); } struct utmpx * getutxline(const struct utmpx *line) { - struct futx *fu; + struct futx fu; for (;;) { - fu = getfutxent(); - if (fu == NULL) + if (getfutxent(&fu) != 0) return (NULL); - switch (fu->fu_type) { + switch (fu.fu_type) { case USER_PROCESS: case LOGIN_PROCESS: - if (strncmp(fu->fu_line, line->ut_line, - MIN(sizeof fu->fu_line, sizeof line->ut_line)) == 0) + if (strncmp(fu.fu_line, line->ut_line, + MIN(sizeof fu.fu_line, sizeof line->ut_line)) == 0) goto found; + break; } } found: - futx_to_utx(fu, &utx); - return (&utx); + return (futx_to_utx(&fu)); } struct utmpx * getutxuser(const char *user) { - struct futx *fu; + struct futx fu; for (;;) { - fu = getfutxent(); - if (fu == NULL) + if (getfutxent(&fu) != 0) return (NULL); - switch (fu->fu_type) { + switch (fu.fu_type) { case USER_PROCESS: - if (strncmp(fu->fu_user, user, sizeof fu->fu_user) == 0) + if (strncmp(fu.fu_user, user, sizeof fu.fu_user) == 0) goto found; + break; } } found: - futx_to_utx(fu, &utx); - return (&utx); + return (futx_to_utx(&fu)); } diff --git a/lib/libc/gen/pututxline.c b/lib/libc/gen/pututxline.c index 94c63bd..1239531 100644 --- a/lib/libc/gen/pututxline.c +++ b/lib/libc/gen/pututxline.c @@ -240,7 +240,6 @@ struct utmpx * pututxline(const struct utmpx *utmpx) { struct futx fu; - static struct utmpx ut; utx_to_futx(utmpx, &fu); @@ -272,6 +271,5 @@ pututxline(const struct utmpx *utmpx) } utx_log_add(&fu); - futx_to_utx(&fu, &ut); - return (&ut); + return (futx_to_utx(&fu)); } diff --git a/lib/libc/gen/utxdb.c b/lib/libc/gen/utxdb.c index d7e2b34..224d86b 100644 --- a/lib/libc/gen/utxdb.c +++ b/lib/libc/gen/utxdb.c @@ -30,6 +30,7 @@ __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include +#include #include #include #include "utxdb.h" @@ -82,6 +83,8 @@ utx_to_futx(const struct utmpx *ut, struct futx *fu) case LOGIN_PROCESS: UTOF_ID(ut, fu); UTOF_STRING(ut, fu, user); + /* XXX: bug in the specification? Needed for getutxline(). */ + UTOF_STRING(ut, fu, line); UTOF_PID(ut, fu); break; case DEAD_PROCESS: @@ -118,11 +121,18 @@ utx_to_futx(const struct utmpx *ut, struct futx *fu) (ut)->ut_tv.tv_usec = t % 1000000; \ } while (0) -void -futx_to_utx(const struct futx *fu, struct utmpx *ut) +struct utmpx * +futx_to_utx(const struct futx *fu) { + static struct utmpx *ut; - memset(ut, 0, sizeof *ut); + if (ut == NULL) { + ut = calloc(1, sizeof *ut); + if (ut == NULL) + return (NULL); + } else { + memset(ut, 0, sizeof *ut); + } switch (fu->fu_type) { case BOOT_TIME: @@ -146,6 +156,8 @@ futx_to_utx(const struct futx *fu, struct utmpx *ut) case LOGIN_PROCESS: FTOU_ID(fu, ut); FTOU_STRING(fu, ut, user); + /* XXX: bug in the specification? Needed for getutxline(). */ + FTOU_STRING(fu, ut, line); FTOU_PID(fu, ut); break; case DEAD_PROCESS: @@ -154,9 +166,10 @@ futx_to_utx(const struct futx *fu, struct utmpx *ut) break; default: ut->ut_type = EMPTY; - return; + return (ut); } FTOU_TYPE(fu, ut); FTOU_TV(fu, ut); + return (ut); } diff --git a/lib/libc/gen/utxdb.h b/lib/libc/gen/utxdb.h index ec02013..d9ebc93 100644 --- a/lib/libc/gen/utxdb.h +++ b/lib/libc/gen/utxdb.h @@ -56,6 +56,6 @@ struct futx { } __packed; void utx_to_futx(const struct utmpx *, struct futx *); -void futx_to_utx(const struct futx *, struct utmpx *); +struct utmpx *futx_to_utx(const struct futx *); #endif /* !_UTXDB_H_ */ -- cgit v1.1 From 630da6fd8a0f711d519e37a59877d72fce80412c Mon Sep 17 00:00:00 2001 From: ache Date: Mon, 18 Jan 2010 10:17:51 +0000 Subject: a) Use strcoll() in opendir() and alphasort() as POSIX 2008 requires. It also matches now how our 'ls' works for years. b) Remove comment expressed 2 fears: 1) One just simple describe how strcoll() works in _any_ context, not for directories only. Are we plan to remove strcoll() from everything just because it is little more complex than strcmp()? I doubt, and directories give nothing different here. Moreover, strcoll() used in 'ls' for years and nobody complaints yet. 2) Plain wrong statement about undefined strcoll() behaviour. strcoll() always gives predictable results, falling back to strcmp() on any trouble, see strcoll(3). No objections from -current list discussion. --- lib/libc/gen/opendir.c | 4 ++-- lib/libc/gen/scandir.c | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/opendir.c b/lib/libc/gen/opendir.c index c192ab2..d99faa4 100644 --- a/lib/libc/gen/opendir.c +++ b/lib/libc/gen/opendir.c @@ -94,13 +94,13 @@ __opendir2(const char *name, int flags) /* * POSIX 2008 and XSI 7 require alphasort() to call strcoll() for - * directory entries ordering. Use local copy that uses strcmp(). + * directory entries ordering. */ static int opendir_alphasort(const void *p1, const void *p2) { - return (strcmp((*(const struct dirent **)p1)->d_name, + return (strcoll((*(const struct dirent **)p1)->d_name, (*(const struct dirent **)p2)->d_name)); } diff --git a/lib/libc/gen/scandir.c b/lib/libc/gen/scandir.c index b6f76ba..2c86aa5 100644 --- a/lib/libc/gen/scandir.c +++ b/lib/libc/gen/scandir.c @@ -127,17 +127,13 @@ fail: /* * Alphabetic order comparison routine for those who want it. * - * XXXKIB POSIX 2008 requires the alphasort() to use strcoll(). Keep - * strcmp() for now, since environment locale settings could have no - * relevance for the byte sequence of the file name. Moreover, it - * might be even invalid sequence in current locale, and then - * behaviour of alphasort would be undefined. + * POSIX 2008 requires the alphasort() to use strcoll(). */ int alphasort(const struct dirent **d1, const struct dirent **d2) { - return (strcmp((*d1)->d_name, (*d2)->d_name)); + return (strcoll((*d1)->d_name, (*d2)->d_name)); } static int -- cgit v1.1 From 553c4a5e4f365e0af1a88fb033ffdac2fe4c4f0b Mon Sep 17 00:00:00 2001 From: davidxu Date: Mon, 18 Jan 2010 10:29:04 +0000 Subject: preserve errno when processing error cases. --- lib/libc/gen/sem_new.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/sem_new.c b/lib/libc/gen/sem_new.c index f513973..ef4ba68 100644 --- a/lib/libc/gen/sem_new.c +++ b/lib/libc/gen/sem_new.c @@ -142,7 +142,7 @@ _sem_open(const char *name, int flags, ...) va_list ap; struct sem_nameinfo *ni = NULL; sem_t *sem = NULL; - int fd = -1, mode, len; + int fd = -1, mode, len, errsave; int value = 0; if (name[0] != '/') { @@ -233,12 +233,14 @@ _sem_open(const char *name, int flags, ...) return (sem); error: + errsave = errno; _pthread_mutex_unlock(&sem_llock); if (fd != -1) _close(fd); if (sem != NULL) munmap(sem, sizeof(sem_t)); free(ni); + errno = errsave; return (SEM_FAILED); } -- cgit v1.1 From c3fd255426edd16af1593a5ff8125bdefa328e56 Mon Sep 17 00:00:00 2001 From: ache Date: Mon, 18 Jan 2010 13:44:44 +0000 Subject: Double checking my commit I found that comment saying that POSIX 2008 and XSI 7require strcoll() for opendir() is not true. I can't find such requirement in POSIX 2008 and XSI 7. So, back out that part of my commit, returning old strcmp(), and remove this misleading comment. --- lib/libc/gen/opendir.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/opendir.c b/lib/libc/gen/opendir.c index d99faa4..dd6d042 100644 --- a/lib/libc/gen/opendir.c +++ b/lib/libc/gen/opendir.c @@ -92,15 +92,11 @@ __opendir2(const char *name, int flags) return __opendir_common(fd, name, flags); } -/* - * POSIX 2008 and XSI 7 require alphasort() to call strcoll() for - * directory entries ordering. - */ static int -opendir_alphasort(const void *p1, const void *p2) +opendir_sort(const void *p1, const void *p2) { - return (strcoll((*(const struct dirent **)p1)->d_name, + return (strcmp((*(const struct dirent **)p1)->d_name, (*(const struct dirent **)p2)->d_name)); } @@ -253,7 +249,7 @@ __opendir_common(int fd, const char *name, int flags) * This sort must be stable. */ mergesort(dpv, n, sizeof(*dpv), - opendir_alphasort); + opendir_sort); dpv[n] = NULL; xp = NULL; -- cgit v1.1 From 863d5d126e582a5f41a69792ba1240089f22d17e Mon Sep 17 00:00:00 2001 From: ed Date: Tue, 19 Jan 2010 23:07:12 +0000 Subject: Revert r202447 by re-exposing the old uname(3) function. It makes hardly any sense to expose a symbol which should only be provided for binary compatibility, but it seems we don't have a lot of choice here. There are many autoconf scripts out there that try to create a binary that links against the old symbol to see whether uname(3) is present. These scripts fail to detect uname(3) now. It should be noted that the behaviour we implement is not against the standards: | The following shall be declared as a function and may also be defined | as a macro: | | int uname(struct utsname *); --- lib/libc/gen/Symbol.map | 1 + lib/libc/gen/uname.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index c21e936..42404bc 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -296,6 +296,7 @@ FBSD_1.0 { tcflow; ualarm; ulimit; + uname; unvis; strunvis; strunvisx; diff --git a/lib/libc/gen/uname.c b/lib/libc/gen/uname.c index 5f8422a..5a7baf7 100644 --- a/lib/libc/gen/uname.c +++ b/lib/libc/gen/uname.c @@ -33,15 +33,15 @@ static char sccsid[] = "From: @(#)uname.c 8.1 (Berkeley) 1/4/94"; #include __FBSDID("$FreeBSD$"); +#define uname wrapped_uname #include #include #include #include +#undef uname int -__uname(struct utsname *name) +uname(struct utsname *name) { return __xuname(32, name); } - -__sym_compat(uname, __uname, FBSD_1.0); -- cgit v1.1 From d9e0a6f31b1a51c571cb2c93fb0adc9399103942 Mon Sep 17 00:00:00 2001 From: ache Date: Wed, 20 Jan 2010 07:27:56 +0000 Subject: Style: remove extra empty line in the comment. Pointed by: bde --- lib/libc/gen/scandir.c | 1 - 1 file changed, 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/scandir.c b/lib/libc/gen/scandir.c index 2c86aa5..2c1bee8 100644 --- a/lib/libc/gen/scandir.c +++ b/lib/libc/gen/scandir.c @@ -126,7 +126,6 @@ fail: /* * Alphabetic order comparison routine for those who want it. - * * POSIX 2008 requires the alphasort() to use strcoll(). */ int -- cgit v1.1 From 6180083f03d0f1b2533b0fc8af51e539000418a2 Mon Sep 17 00:00:00 2001 From: ache Date: Wed, 20 Jan 2010 07:36:29 +0000 Subject: Style: rename internal function to opendir_compar() Pointed by: bde --- lib/libc/gen/opendir.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/opendir.c b/lib/libc/gen/opendir.c index dd6d042..b312c89 100644 --- a/lib/libc/gen/opendir.c +++ b/lib/libc/gen/opendir.c @@ -93,7 +93,7 @@ __opendir2(const char *name, int flags) } static int -opendir_sort(const void *p1, const void *p2) +opendir_compar(const void *p1, const void *p2) { return (strcmp((*(const struct dirent **)p1)->d_name, @@ -249,7 +249,7 @@ __opendir_common(int fd, const char *name, int flags) * This sort must be stable. */ mergesort(dpv, n, sizeof(*dpv), - opendir_sort); + opendir_compar); dpv[n] = NULL; xp = NULL; -- cgit v1.1 From 428cfaa66eaa12399ad521d9b0e272afc46ff702 Mon Sep 17 00:00:00 2001 From: ache Date: Wed, 20 Jan 2010 11:55:14 +0000 Subject: For alphasort() add reference to strcoll(3) --- lib/libc/gen/scandir.3 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/scandir.3 b/lib/libc/gen/scandir.3 index 5e177b9..e32b0d8 100644 --- a/lib/libc/gen/scandir.3 +++ b/lib/libc/gen/scandir.3 @@ -81,7 +81,8 @@ The function is a routine which can be used for the .Fa compar -argument to sort the array alphabetically. +argument to sort the array alphabetically using +.Xr strcoll 3 . .Pp The memory allocated for the array can be deallocated with .Xr free 3 , @@ -94,7 +95,8 @@ cannot allocate enough memory to hold all the data structures. .Xr directory 3 , .Xr malloc 3 , .Xr qsort 3 , -.Xr dir 5 +.Xr dir 5 , +.Xr strcoll 3 .Sh HISTORY The .Fn scandir -- cgit v1.1 From fcb9d629ca940121446014db94539ed245fe3736 Mon Sep 17 00:00:00 2001 From: ache Date: Wed, 20 Jan 2010 11:59:46 +0000 Subject: Style: reword comment. Submitted by: bde --- lib/libc/gen/scandir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/scandir.c b/lib/libc/gen/scandir.c index 2c1bee8..93bc852 100644 --- a/lib/libc/gen/scandir.c +++ b/lib/libc/gen/scandir.c @@ -126,7 +126,7 @@ fail: /* * Alphabetic order comparison routine for those who want it. - * POSIX 2008 requires the alphasort() to use strcoll(). + * POSIX 2008 requires that alphasort() uses strcoll(). */ int alphasort(const struct dirent **d1, const struct dirent **d2) -- cgit v1.1 From 9fe217e5416e97a68bca734f4b20dec337129de6 Mon Sep 17 00:00:00 2001 From: pjd Date: Wed, 20 Jan 2010 22:26:36 +0000 Subject: The waitpid(2) function needs neither sys/time.h nor sys/resource.h. --- lib/libc/sys/wait.2 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/sys/wait.2 b/lib/libc/sys/wait.2 index c492cd6..2e084d2 100644 --- a/lib/libc/sys/wait.2 +++ b/lib/libc/sys/wait.2 @@ -44,10 +44,10 @@ .In sys/wait.h .Ft pid_t .Fn wait "int *status" -.In sys/time.h -.In sys/resource.h .Ft pid_t .Fn waitpid "pid_t wpid" "int *status" "int options" +.In sys/time.h +.In sys/resource.h .Ft pid_t .Fn wait3 "int *status" "int options" "struct rusage *rusage" .Ft pid_t -- cgit v1.1 From 64eeb2f5c81f164f538188766a50df190eb4545c Mon Sep 17 00:00:00 2001 From: gabor Date: Thu, 21 Jan 2010 11:36:40 +0000 Subject: - Update Galician catalog --- lib/libc/nls/gl_ES.ISO8859-1.msg | 46 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/nls/gl_ES.ISO8859-1.msg b/lib/libc/nls/gl_ES.ISO8859-1.msg index d97615f..4255dc8 100644 --- a/lib/libc/nls/gl_ES.ISO8859-1.msg +++ b/lib/libc/nls/gl_ES.ISO8859-1.msg @@ -181,6 +181,16 @@ $ ENOATTR 87 Atributo non encontrado $ EDOOFUS 88 Erro de programacin +$ EBADMSG +89 Mensaxe invlido +$ EMULTIHOP +90 Intento de Multihop +$ ENOLINK +91 Enlace fortaleceuse +$ EPROTO +92 Erro de protocolo +$ ENOTCAPABLE +93 Habilidades non suficientes $ $ strsignal() support catalog $ @@ -247,3 +257,39 @@ $ SIGUSR1 30 Sinal definida polo usuario no. 1 $ SIGUSR2 31 Sinal definida polo usuario no. 2 +$ +$ gai_strerror() support catalog +$ +$set 3 +$ 1 (obsoleto) +1 Tipo de direccin non soportado +$ EAI_AGAIN +2 Erro temporal na resolucin de nomes +$ EAI_BADFLAGS +3 Valor invlido de ai_flags +$ EAI_FAIL +4 Erro non recuperable na resolucin de nomes +$ EAI_FAMILY +5 ai_family non soportado +$ EAI_MEMORY +6 Erro na asignacin de memoria +$ 7 (obsoleto) +7 Non hai direccin asociada co nome de mquina +$ EAI_NONAME +8 Non se dispn nome de mquina, nin nome de servizo +$ EAI_SERVICE +9 Nome de servizo non soportado en ai_socktype +$ EAI_SOCKTYPE +10 ai_socktype non soportado +$ EAI_SYSTEM +11 Erro de sistema devolto en errno +$ EAI_BADHINTS +12 Valor invlido de hints +$ EAI_PROTOCOL +13 Protocolo resolto descoecido +$ EAI_OVERFLOW +14 Bfer de argumentos excedido +$ 0 +32766 xito +$ NL_MSGMAX +32767 Erro descoecido -- cgit v1.1 From e175594ed6eabbf2370dbe1493450a8ed3cd965d Mon Sep 17 00:00:00 2001 From: ed Date: Fri, 22 Jan 2010 04:53:08 +0000 Subject: Remove comments about breaking the specification. I've discussed this issue with the Austin Group and it will be fixed in future revisions of the specification. The issue was that ut_line fields weren't supposed to be valid for LOGIN_PROCESS entries, while getutxline() would try to match these records anyway. They also agreed on our way of implementing pututxline() without getutxid() (which other operating systems also do), but unfortunately they disagreed with our way of replacing DEAD_PROCESS entries, which is a pity. The current specification allows the utmpx database to become infinitely big over time. See also: http://austingroupbugs.net/view.php?id=213#c378 --- lib/libc/gen/utxdb.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/utxdb.c b/lib/libc/gen/utxdb.c index 224d86b..49118ff 100644 --- a/lib/libc/gen/utxdb.c +++ b/lib/libc/gen/utxdb.c @@ -83,7 +83,6 @@ utx_to_futx(const struct utmpx *ut, struct futx *fu) case LOGIN_PROCESS: UTOF_ID(ut, fu); UTOF_STRING(ut, fu, user); - /* XXX: bug in the specification? Needed for getutxline(). */ UTOF_STRING(ut, fu, line); UTOF_PID(ut, fu); break; @@ -156,7 +155,6 @@ futx_to_utx(const struct futx *fu) case LOGIN_PROCESS: FTOU_ID(fu, ut); FTOU_STRING(fu, ut, user); - /* XXX: bug in the specification? Needed for getutxline(). */ FTOU_STRING(fu, ut, line); FTOU_PID(fu, ut); break; -- cgit v1.1 From a14af867093d4252dca678cc2623ff485f5fcf3d Mon Sep 17 00:00:00 2001 From: ed Date: Fri, 22 Jan 2010 05:09:10 +0000 Subject: Describe why pututxline() doesn't entirely conform to standards. --- lib/libc/gen/getutxent.3 | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/getutxent.3 b/lib/libc/gen/getutxent.3 index 58b1280..5098afe 100644 --- a/lib/libc/gen/getutxent.3 +++ b/lib/libc/gen/getutxent.3 @@ -414,14 +414,32 @@ The .Fn endutxent , .Fn getutxent , .Fn getutxid , -.Fn getutxline , -.Fn pututxline +.Fn getutxline and .Fn setutxent functions are expected to conform to .St -p1003.1-2008 . .Pp The +.Fn pututxline +function deviates from the standard by writing its records to multiple +database files, depending on its +.Fa ut_type . +This prevents the need for special utility functions to update the other +databases, such as the +.Fn updwtmpx +function which is often available in other implementations. +It also tries to replace +.Dv DEAD_PROCESS +entries in the active sessions database when storing +.Dv USER_PROCESS +entries and no entry with the same value for +.Fa ut_id +has been found. +The standard always requires a new entry to be allocated, which could +cause an unbounded growth to the database. +.Pp +The .Fn getutxuser and .Fn setutxdb -- cgit v1.1 From 3e653995ff38c9c50d393bf9be6185a216e21098 Mon Sep 17 00:00:00 2001 From: ed Date: Fri, 22 Jan 2010 05:19:51 +0000 Subject: English nitpicking. Submitted by: jmallett --- lib/libc/gen/getutxent.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/getutxent.3 b/lib/libc/gen/getutxent.3 index 5098afe..7436142 100644 --- a/lib/libc/gen/getutxent.3 +++ b/lib/libc/gen/getutxent.3 @@ -437,7 +437,7 @@ entries and no entry with the same value for .Fa ut_id has been found. The standard always requires a new entry to be allocated, which could -cause an unbounded growth to the database. +cause an unbounded growth of the database. .Pp The .Fn getutxuser -- cgit v1.1 From a7d4005f80a992c3d31951774fbda2cf95479028 Mon Sep 17 00:00:00 2001 From: ed Date: Sat, 23 Jan 2010 08:43:21 +0000 Subject: Just ignore the timestamps given to pututxline(). I've noticed many applications do a bad job at timekeeping, for several reasons: - Applications like screen(1) don't update time records when restoring the old user login record. - Many applications only set ut_tv.tv_sec, not ut_tv.tv_usec. This causes many problems for tools such as ac(8), which require the timestamps to be properly ordered. This is why I've decided to let the utmpx code obtain valid timestamps itself. --- lib/libc/gen/getutxent.3 | 12 +++++------- lib/libc/gen/pututxline.c | 12 ------------ lib/libc/gen/utxdb.c | 11 +++++++---- 3 files changed, 12 insertions(+), 23 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/getutxent.3 b/lib/libc/gen/getutxent.3 index 7436142..37080bb 100644 --- a/lib/libc/gen/getutxent.3 +++ b/lib/libc/gen/getutxent.3 @@ -311,13 +311,9 @@ will only be written to Entries of type .Dv USER_PROCESS will also be written to -.Pa /var/run/utx.active . -It will only be written to -.Pa /var/log/utx.lastlogin -if -.Fa ut_tv -for that user has a greater value than the existing entry or when no -entry for the user has been found. +.Pa /var/run/utx.active +and +.Pa /var/log/utx.lastlogin . .Pp Entries of type .Dv DEAD_PROCESS @@ -345,6 +341,8 @@ to be discarded. All entries whose type has not been mentioned previously, are discarded by this implementation of .Fn pututxline . +This implementation also ignores the value of +.Fa ut_tv . .Sh RETURN VALUES The .Fn getutxent , diff --git a/lib/libc/gen/pututxline.c b/lib/libc/gen/pututxline.c index 1239531..ce4dc28 100644 --- a/lib/libc/gen/pututxline.c +++ b/lib/libc/gen/pututxline.c @@ -132,13 +132,6 @@ utx_active_remove(struct futx *fu) if (memcmp(fu->fu_id, fe.fu_id, sizeof fe.fu_id) != 0) continue; - /* - * Prevent login sessions from having a negative - * timespan. - */ - if (be64toh(fu->fu_tv) < be64toh(fe.fu_tv)) - fu->fu_tv = fe.fu_tv; - /* Terminate session. */ fseeko(fp, -(off_t)sizeof fe, SEEK_CUR); fwrite(fu, sizeof *fu, 1, fp); @@ -175,17 +168,12 @@ utx_lastlogin_add(const struct futx *fu) while (fread(&fe, sizeof fe, 1, fp) == 1) { if (strncmp(fu->fu_user, fe.fu_user, sizeof fe.fu_user) != 0) continue; - - /* Prevent lowering the time value. */ - if (be64toh(fu->fu_tv) <= be64toh(fe.fu_tv)) - goto done; /* Found a previous lastlogin entry for this user. */ fseeko(fp, -(off_t)sizeof fe, SEEK_CUR); break; } fwrite(fu, sizeof *fu, 1, fp); -done: fclose(fp); } diff --git a/lib/libc/gen/utxdb.c b/lib/libc/gen/utxdb.c index 49118ff..6a85c05 100644 --- a/lib/libc/gen/utxdb.c +++ b/lib/libc/gen/utxdb.c @@ -30,6 +30,7 @@ __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include +#include #include #include #include @@ -50,9 +51,11 @@ __FBSDID("$FreeBSD$"); #define UTOF_TYPE(ut, fu) do { \ (fu)->fu_type = (ut)->ut_type; \ } while (0) -#define UTOF_TV(ut, fu) do { \ - (fu)->fu_tv = htobe64((uint64_t)(ut)->ut_tv.tv_sec * 1000000 + \ - (uint64_t)(ut)->ut_tv.tv_usec); \ +#define UTOF_TV(fu) do { \ + struct timeval tv; \ + gettimeofday(&tv, NULL); \ + (fu)->fu_tv = htobe64((uint64_t)tv.tv_sec * 1000000 + \ + (uint64_t)tv.tv_usec); \ } while (0) void @@ -96,7 +99,7 @@ utx_to_futx(const struct utmpx *ut, struct futx *fu) } UTOF_TYPE(ut, fu); - UTOF_TV(ut, fu); + UTOF_TV(fu); } #define FTOU_STRING(fu, ut, field) do { \ -- cgit v1.1 From 233af5fd9317397ad5b62c55c60c9713ea1bed86 Mon Sep 17 00:00:00 2001 From: antoine Date: Sat, 23 Jan 2010 12:48:46 +0000 Subject: Reapply r201145 to lib/libc/gen/sem.c --- lib/libc/gen/sem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/sem.c b/lib/libc/gen/sem.c index 7cb021c..628e650 100644 --- a/lib/libc/gen/sem.c +++ b/lib/libc/gen/sem.c @@ -106,7 +106,7 @@ typedef struct sem* sem_t; static sem_t sem_alloc(unsigned int value, semid_t semid, int system_sem); static void sem_free(sem_t sem); -static LIST_HEAD(, sem) named_sems = LIST_HEAD_INITIALIZER(&named_sems); +static LIST_HEAD(, sem) named_sems = LIST_HEAD_INITIALIZER(named_sems); static pthread_mutex_t named_sems_mtx = PTHREAD_MUTEX_INITIALIZER; FB10_COMPAT(_libc_sem_init_compat, sem_init); -- cgit v1.1 From 3f4b8c890828e53d4cda96f6ebafb4b30e27d7aa Mon Sep 17 00:00:00 2001 From: ed Date: Sat, 23 Jan 2010 17:58:40 +0000 Subject: EMPTY records don't have a timestamp. --- lib/libc/gen/getutxent.3 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/getutxent.3 b/lib/libc/gen/getutxent.3 index 37080bb..0b29807 100644 --- a/lib/libc/gen/getutxent.3 +++ b/lib/libc/gen/getutxent.3 @@ -138,7 +138,8 @@ Other fields inside the structure are: .Bl -tag -width ut_user .It Fa ut_tv The time the event occured. -This field is used for all types of entries. +This field is used for all types of entries, except +.Dv EMPTY . .It Fa ut_id An identifier that is used to refer to the entry. This identifier can be used to remove or replace a login entry by -- cgit v1.1 From 613ef8622623d2439e73e28d105485935e979d44 Mon Sep 17 00:00:00 2001 From: ume Date: Sun, 24 Jan 2010 10:35:26 +0000 Subject: Make strsignal(3) thread-safe. MFC after: 2 weeks --- lib/libc/string/strsignal.c | 52 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/string/strsignal.c b/lib/libc/string/strsignal.c index e4267a3..c51f34d 100644 --- a/lib/libc/string/strsignal.c +++ b/lib/libc/string/strsignal.c @@ -33,22 +33,64 @@ static char sccsid[] = "@(#)strerror.c 8.1 (Berkeley) 6/4/93"; #include __FBSDID("$FreeBSD$"); +#include "namespace.h" #if defined(NLS) #include #endif - #include #include +#include #include #include +#include "reentrant.h" +#include "un-namespace.h" #define UPREFIX "Unknown signal" +static char sig_ebuf[NL_TEXTMAX]; +static char sig_ebuf_err[NL_TEXTMAX]; +static once_t sig_init_once = ONCE_INITIALIZER; +static thread_key_t sig_key; +static int sig_keycreated = 0; + +static void +sig_keycreate(void) +{ + sig_keycreated = (thr_keycreate(&sig_key, free) == 0); +} + +static char * +sig_tlsalloc(void) +{ + char *ebuf = NULL; + + if (thr_main() != 0) + ebuf = sig_ebuf; + else { + if (thr_once(&sig_init_once, sig_keycreate) != 0 || + !sig_keycreated) + goto thr_err; + if ((ebuf = thr_getspecific(sig_key)) == NULL) { + if ((ebuf = malloc(sizeof(sig_ebuf))) == NULL) + goto thr_err; + if (thr_setspecific(sig_key, ebuf) != 0) { + free(ebuf); + ebuf = NULL; + goto thr_err; + } + } + } +thr_err: + if (ebuf == NULL) + ebuf = sig_ebuf_err; + return (ebuf); +} + /* XXX: negative 'num' ? (REGR) */ char * strsignal(int num) { - static char ebuf[NL_TEXTMAX]; + char *ebuf; char tmp[20]; size_t n; int signum; @@ -60,6 +102,8 @@ strsignal(int num) catd = catopen("libc", NL_CAT_LOCALE); #endif + ebuf = sig_tlsalloc(); + if (num > 0 && num < sys_nsig) { n = strlcpy(ebuf, #if defined(NLS) @@ -67,7 +111,7 @@ strsignal(int num) #else sys_siglist[num], #endif - sizeof(ebuf)); + sizeof(sig_ebuf)); } else { n = strlcpy(ebuf, #if defined(NLS) @@ -75,7 +119,7 @@ strsignal(int num) #else UPREFIX, #endif - sizeof(ebuf)); + sizeof(sig_ebuf)); } signum = num; -- cgit v1.1 From a2ddef4efb5d078a5dbc5b621b3655da63a16c7f Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 24 Jan 2010 14:44:05 +0000 Subject: Improve the ttyname(3) manual page. - Remove unrelated references to tty(5). - Remove unneeded relation with FILE *. - Add better cross references. --- lib/libc/gen/ttyname.3 | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/ttyname.3 b/lib/libc/gen/ttyname.3 index e583833..9420bbe 100644 --- a/lib/libc/gen/ttyname.3 +++ b/lib/libc/gen/ttyname.3 @@ -47,19 +47,7 @@ .Ft int .Fn isatty "int fd" .Sh DESCRIPTION -These functions operate on the system file descriptors for terminal -type devices. -These descriptors are not related to the standard -.Tn I/O -.Dv FILE -typedef, but refer to the special device files found in -.Pa /dev -and for which an entry exists -in the initialization file -.Pa /etc/ttys -or pseudo-terminals. -(See -.Xr ttys 5 . ) +These functions operate on file descriptors for terminal type devices. .Pp The .Fn isatty @@ -100,11 +88,6 @@ The .Fn ttyname_r function returns 0 if successful. Otherwise an error number is returned. -.Sh FILES -.Bl -tag -width ".Pa /etc/ttys" -compact -.It Pa /dev/\(** -.It Pa /etc/ttys -.El .Sh ERRORS The .Fn ttyname_r @@ -122,8 +105,10 @@ argument is smaller than the length of the string to be returned. .El .Sh SEE ALSO -.Xr ioctl 2 , -.Xr ttys 5 +.Xr fdevname 3 , +.Xr ptsname 3 , +.Xr tcgetattr 3 , +.Xr tty 4 .Sh HISTORY The .Fn isatty -- cgit v1.1 From b9c96fa7354a55918bde621a35e90ddc09ec5ca4 Mon Sep 17 00:00:00 2001 From: gabor Date: Mon, 25 Jan 2010 23:37:49 +0000 Subject: Cache failing and opened catalogs in catopen() and related functions. Continuous catopen() calls cause 4 failig stat(2) each, which means a lot of overhead. It is also a good idea to keep the opened catalogs in the memory to speed up further catopen() calls to the same catalog since these catalogs are not big at all. In this case, we count references and only free() the allocated space when the reference count reaches 0. The reads and writes to the cache are syncronized with an rwlock when these functions are called from a threaded program. Requested by: kib Approved by: delphij --- lib/libc/nls/msgcat.c | 148 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 131 insertions(+), 17 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/nls/msgcat.c b/lib/libc/nls/msgcat.c index 8689b7e..ce73965 100644 --- a/lib/libc/nls/msgcat.c +++ b/lib/libc/nls/msgcat.c @@ -1,5 +1,6 @@ /*********************************************************** Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts. +Copyright 2010, Gabor Kovesdan All Rights Reserved @@ -39,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include /* for ntohl() */ @@ -47,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -57,10 +60,49 @@ __FBSDID("$FreeBSD$"); #define _DEFAULT_NLS_PATH "/usr/share/nls/%L/%N.cat:/usr/share/nls/%N/%L:/usr/local/share/nls/%L/%N.cat:/usr/local/share/nls/%N/%L" +#define RLOCK(fail) { int ret; \ + if (__isthreaded && \ + ((ret = _pthread_rwlock_rdlock(&rwlock)) != 0)) { \ + errno = ret; \ + return (fail); \ + }} +#define WLOCK(fail) { int ret; \ + if (__isthreaded && \ + ((ret = _pthread_rwlock_wrlock(&rwlock)) != 0)) { \ + errno = ret; \ + return (fail); \ + }} +#define UNLOCK { if (__isthreaded) \ + _pthread_rwlock_unlock(&rwlock); } + #define NLERR ((nl_catd) -1) #define NLRETERR(errc) { errno = errc; return (NLERR); } +#define SAVEFAIL(n, e) { WLOCK(NLERR); \ + np = malloc(sizeof(struct catentry)); \ + if (np != NULL) { \ + np->name = strdup(n); \ + np->caterrno = e; \ + SLIST_INSERT_HEAD(&cache, np, list); \ + } \ + UNLOCK; \ + } + +static nl_catd load_msgcat(const char *, const char *, const char *); + +static pthread_rwlock_t rwlock; -static nl_catd load_msgcat(const char *); +struct catentry { + SLIST_ENTRY(catentry) list; + char *name; + char *path; + int caterrno; + nl_catd catd; + char *lang; + int refcount; +}; + +SLIST_HEAD(listhead, catentry) cache = + SLIST_HEAD_INITIALIZER(cache); nl_catd catopen(const char *name, int type) @@ -70,14 +112,14 @@ catopen(const char *name, int type) char *nlspath, *lang, *base, *cptr, *pathP, *tmpptr; char *cptr1, *plang, *pter, *pcode; struct stat sbuf; + struct catentry *np; if (name == NULL || *name == '\0') NLRETERR(EINVAL); - /* is it absolute path ? if yes, load immediately */ if (strchr(name, '/') != NULL) - return (load_msgcat(name)); - + lang = NULL; + else { if (type == NL_CAT_LOCALE) lang = setlocale(LC_MESSAGES, NULL); else @@ -88,6 +130,29 @@ catopen(const char *name, int type) (lang[1] == '\0' || (lang[1] == '.' && lang[2] == '\0'))) || strchr(lang, '/') != NULL) lang = "C"; + } + + /* Try to get it from the cache first */ + RLOCK(NLERR); + SLIST_FOREACH(np, &cache, list) { + if (strcmp(np->name, name) == 0) { + if (np->caterrno != 0) { + /* Found cached failing entry */ + UNLOCK; + NLRETERR(np->caterrno); + } else if (strcmp(np->lang, lang) == 0) { + /* Found cached successful entry */ + np->refcount++; + UNLOCK; + return (np->catd); + } + } + } + UNLOCK; + + /* is it absolute path ? if yes, load immediately */ + if (strchr(name, '/') != NULL) + return (load_msgcat(name, name, lang)); if ((plang = cptr1 = strdup(lang)) == NULL) return (NLERR); @@ -166,7 +231,7 @@ catopen(const char *name, int type) if (stat(path, &sbuf) == 0) { free(plang); free(base); - return (load_msgcat(path)); + return (load_msgcat(path, name, lang)); } } else { tmpptr = (char *)name; @@ -190,12 +255,12 @@ catgets(nl_catd catd, int set_id, int msg_id, const char *s) if (catd == NULL || catd == NLERR) { errno = EBADF; /* LINTED interface problem */ - return (char *) s; -} + return ((char *)s); + } - cat_hdr = (struct _nls_cat_hdr *)catd->__data; - set_hdr = (struct _nls_set_hdr *)(void *)((char *)catd->__data - + sizeof(struct _nls_cat_hdr)); + cat_hdr = (struct _nls_cat_hdr *)catd->__data; + set_hdr = (struct _nls_set_hdr *)(void *)((char *)catd->__data + + sizeof(struct _nls_cat_hdr)); /* binary search, see knuth algorithm b */ l = 0; @@ -228,7 +293,7 @@ catgets(nl_catd catd, int set_id, int msg_id, const char *s) } else { l = i + 1; } -} + } /* not found */ goto notfound; @@ -238,25 +303,41 @@ catgets(nl_catd catd, int set_id, int msg_id, const char *s) } else { l = i + 1; } -} + } notfound: /* not found */ errno = ENOMSG; /* LINTED interface problem */ - return (char *) s; + return ((char *)s); } int catclose(nl_catd catd) { + struct catentry *np; + if (catd == NULL || catd == NLERR) { errno = EBADF; return (-1); } + /* Remove from cache if not referenced any more */ + WLOCK(-1); + SLIST_FOREACH(np, &cache, list) { + if ((np->catd->__size == catd->__size) && + memcmp((const void *)np->catd, (const void *)catd, np->catd->__size) == 0) { + np->refcount--; + if (np->refcount == 0) { munmap(catd->__data, (size_t)catd->__size); free(catd); + SLIST_REMOVE(&cache, np, catentry, list); + free(np); + } + break; + } + } + UNLOCK; return (0); } @@ -265,19 +346,35 @@ catclose(nl_catd catd) */ static nl_catd -load_msgcat(const char *path) +load_msgcat(const char *path, const char *name, const char *lang) { struct stat st; nl_catd catd; + struct catentry *np; void *data; int fd; - /* XXX: path != NULL? */ + /* path/name will never be NULL here */ + + /* One more try in cache; if it was not found by name, + it might still be found by absolute path. */ + RLOCK(NLERR); + SLIST_FOREACH(np, &cache, list) { + if (strcmp(np->path, path) == 0) { + np->refcount++; + UNLOCK; + return (np->catd); + } + } + UNLOCK; - if ((fd = _open(path, O_RDONLY)) == -1) + if ((fd = _open(path, O_RDONLY)) == -1) { + SAVEFAIL(name, errno); return (NLERR); + } if (_fstat(fd, &st) != 0) { + SAVEFAIL(name, errno); _close(fd); return (NLERR); } @@ -286,22 +383,39 @@ load_msgcat(const char *path) (off_t)0); _close(fd); - if (data == MAP_FAILED) + if (data == MAP_FAILED) { + SAVEFAIL(name, errno); return (NLERR); + } if (ntohl((u_int32_t)((struct _nls_cat_hdr *)data)->__magic) != _NLS_MAGIC) { + SAVEFAIL(name, errno); munmap(data, (size_t)st.st_size); NLRETERR(EINVAL); } if ((catd = malloc(sizeof (*catd))) == NULL) { + SAVEFAIL(name, errno); munmap(data, (size_t)st.st_size); return (NLERR); } catd->__data = data; catd->__size = (int)st.st_size; + + /* Caching opened catalog */ + WLOCK(NLERR); + if ((np = malloc(sizeof(struct catentry))) != NULL) { + np->name = strdup(name); + np->path = strdup(path); + np->catd = catd; + np->lang = (lang == NULL) ? NULL : strdup(lang); + np->refcount = 1; + np->caterrno = 0; + SLIST_INSERT_HEAD(&cache, np, list); + } + UNLOCK; return (catd); } -- cgit v1.1 From 5cd5dea33bd9e5836617934509e913f7c130c4d8 Mon Sep 17 00:00:00 2001 From: gabor Date: Mon, 25 Jan 2010 23:44:00 +0000 Subject: - style(9) Approved by: delphij --- lib/libc/nls/msgcat.c | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/nls/msgcat.c b/lib/libc/nls/msgcat.c index ce73965..0809d8a 100644 --- a/lib/libc/nls/msgcat.c +++ b/lib/libc/nls/msgcat.c @@ -107,11 +107,11 @@ SLIST_HEAD(listhead, catentry) cache = nl_catd catopen(const char *name, int type) { - int spcleft, saverr; - char path[PATH_MAX]; - char *nlspath, *lang, *base, *cptr, *pathP, *tmpptr; - char *cptr1, *plang, *pter, *pcode; - struct stat sbuf; + int spcleft, saverr; + char path[PATH_MAX]; + char *nlspath, *lang, *base, *cptr, *pathP, *tmpptr; + char *cptr1, *plang, *pter, *pcode; + struct stat sbuf; struct catentry *np; if (name == NULL || *name == '\0') @@ -120,16 +120,16 @@ catopen(const char *name, int type) if (strchr(name, '/') != NULL) lang = NULL; else { - if (type == NL_CAT_LOCALE) - lang = setlocale(LC_MESSAGES, NULL); - else - lang = getenv("LANG"); - - if (lang == NULL || *lang == '\0' || strlen(lang) > ENCODING_LEN || - (lang[0] == '.' && - (lang[1] == '\0' || (lang[1] == '.' && lang[2] == '\0'))) || - strchr(lang, '/') != NULL) - lang = "C"; + if (type == NL_CAT_LOCALE) + lang = setlocale(LC_MESSAGES, NULL); + else + lang = getenv("LANG"); + + if (lang == NULL || *lang == '\0' || strlen(lang) > ENCODING_LEN || + (lang[0] == '.' && + (lang[1] == '\0' || (lang[1] == '.' && lang[2] == '\0'))) || + strchr(lang, '/') != NULL) + lang = "C"; } /* Try to get it from the cache first */ @@ -247,10 +247,10 @@ catopen(const char *name, int type) char * catgets(nl_catd catd, int set_id, int msg_id, const char *s) { - struct _nls_cat_hdr *cat_hdr; - struct _nls_set_hdr *set_hdr; - struct _nls_msg_hdr *msg_hdr; - int l, u, i, r; + struct _nls_cat_hdr *cat_hdr; + struct _nls_set_hdr *set_hdr; + struct _nls_msg_hdr *msg_hdr; + int l, u, i, r; if (catd == NULL || catd == NLERR) { errno = EBADF; @@ -329,8 +329,8 @@ catclose(nl_catd catd) memcmp((const void *)np->catd, (const void *)catd, np->catd->__size) == 0) { np->refcount--; if (np->refcount == 0) { - munmap(catd->__data, (size_t)catd->__size); - free(catd); + munmap(catd->__data, (size_t)catd->__size); + free(catd); SLIST_REMOVE(&cache, np, catentry, list); free(np); } @@ -348,11 +348,11 @@ catclose(nl_catd catd) static nl_catd load_msgcat(const char *path, const char *name, const char *lang) { - struct stat st; - nl_catd catd; + struct stat st; + nl_catd catd; struct catentry *np; - void *data; - int fd; + void *data; + int fd; /* path/name will never be NULL here */ -- cgit v1.1 From 85c20ff770df6c2f7bea1f7f240843b3779ff895 Mon Sep 17 00:00:00 2001 From: trasz Date: Tue, 26 Jan 2010 17:21:25 +0000 Subject: Add information about when nmount(2) was introduced. --- lib/libc/sys/mount.2 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/sys/mount.2 b/lib/libc/sys/mount.2 index 6ce2d4d..b65c1b6 100644 --- a/lib/libc/sys/mount.2 +++ b/lib/libc/sys/mount.2 @@ -28,7 +28,7 @@ .\" @(#)mount.2 8.3 (Berkeley) 5/24/95 .\" $FreeBSD$ .\" -.Dd February 23, 2005 +.Dd January 26, 2010 .Dt MOUNT 2 .Os .Sh NAME @@ -368,5 +368,9 @@ and .Fn unmount functions appeared in .At v6 . +The +.Fn nmount +system call first appeared in +.Fx 5.0 . .Sh BUGS Some of the error codes need translation to more obvious messages. -- cgit v1.1 From 93642d99973a88335db8126f637ce0b2ef249f6d Mon Sep 17 00:00:00 2001 From: ed Date: Wed, 27 Jan 2010 11:54:42 +0000 Subject: Remove pseudo-terminals from ttys(5). When we had utmp(5), we had to list all the psuedo-terminals in ttys(5) to make ttyslot(3) function properly. Now that pututxline(3) deals with slot allocation internally (not based on TTY names), we don't need to list all the TTYs on the system in ttys(5) to make user accounting work properly. This patch removes all the entries from the /etc/ttys files, but also the pts(4) entries that were appended implicitly, which was added in r154838. --- lib/libc/gen/getttyent.c | 37 +------------------------------------ 1 file changed, 1 insertion(+), 36 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/getttyent.c b/lib/libc/gen/getttyent.c index 99d9821..9b9e3ea 100644 --- a/lib/libc/gen/getttyent.c +++ b/lib/libc/gen/getttyent.c @@ -38,17 +38,12 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include static char zapchar; static FILE *tf; -static int maxpts = -1; -static int curpts = 0; static size_t lbsize; static char *line; -#define PTS "pts/" #define MALLOCCHUNK 100 static char *skip(char *); @@ -73,7 +68,6 @@ struct ttyent * getttyent(void) { static struct ttyent tty; - static char devpts_name[] = "pts/4294967295"; char *p; int c; size_t i; @@ -81,19 +75,8 @@ getttyent(void) if (!tf && !setttyent()) return (NULL); for (;;) { - if (!fgets(p = line, lbsize, tf)) { - if (curpts <= maxpts) { - sprintf(devpts_name, "pts/%d", curpts++); - tty.ty_name = devpts_name; - tty.ty_getty = tty.ty_type = NULL; - tty.ty_status = TTY_NETWORK; - tty.ty_window = NULL; - tty.ty_comment = NULL; - tty.ty_group = _TTYS_NOGROUP; - return (&tty); - } + if (!fgets(p = line, lbsize, tf)) return (NULL); - } /* extend buffer if line was too big, and retry */ while (!index(p, '\n') && !feof(tf)) { i = strlen(p); @@ -219,29 +202,12 @@ value(char *p) int setttyent(void) { - DIR *devpts_dir; if (line == NULL) { if ((line = malloc(MALLOCCHUNK)) == NULL) return (0); lbsize = MALLOCCHUNK; } - devpts_dir = opendir(_PATH_DEV PTS); - if (devpts_dir) { - struct dirent *dp; - - maxpts = -1; - while ((dp = readdir(devpts_dir))) { - if (strcmp(dp->d_name, ".") != 0 && - strcmp(dp->d_name, "..") != 0) { - if (atoi(dp->d_name) > maxpts) { - maxpts = atoi(dp->d_name); - curpts = 0; - } - } - } - closedir(devpts_dir); - } if (tf) { rewind(tf); return (1); @@ -255,7 +221,6 @@ endttyent(void) { int rval; - maxpts = -1; /* * NB: Don't free `line' because getttynam() * may still be referencing it -- cgit v1.1 From fd88d82b16b214377a780481a0df28bb852bd87f Mon Sep 17 00:00:00 2001 From: emaste Date: Wed, 27 Jan 2010 16:47:02 +0000 Subject: Add missing return, in a rare case where we can't allocate memory in deallocate. Submitted by: Ryan Stone (rysto32 at gmail dot com) Approved by: jasone --- lib/libc/stdlib/malloc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/libc') diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c index e1b3f33..bf862e2 100644 --- a/lib/libc/stdlib/malloc.c +++ b/lib/libc/stdlib/malloc.c @@ -3800,6 +3800,7 @@ arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr) arena_dalloc_small(arena, chunk, ptr, mapelm); malloc_spin_unlock(&arena->lock); + return; } mag_rack = rack; } -- cgit v1.1 From f403000d3914d84750322e39d1292d2420d88026 Mon Sep 17 00:00:00 2001 From: rwatson Date: Fri, 29 Jan 2010 10:32:01 +0000 Subject: You must include fcntl.h (in practice) to be able to do anything useful with shm_open(2), as otherwise the O_ flags are undefined. MFC after: 3 days --- lib/libc/sys/shm_open.2 | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/libc') diff --git a/lib/libc/sys/shm_open.2 b/lib/libc/sys/shm_open.2 index 5c5d694..a586fe3 100644 --- a/lib/libc/sys/shm_open.2 +++ b/lib/libc/sys/shm_open.2 @@ -39,6 +39,7 @@ .Sh SYNOPSIS .In sys/types.h .In sys/mman.h +.In fcntl.h .Ft int .Fn shm_open "const char *path" "int flags" "mode_t mode" .Ft int -- cgit v1.1 From e93ffcfe03e4683be2bc3edc70f32439dc4ccb88 Mon Sep 17 00:00:00 2001 From: gabor Date: Fri, 29 Jan 2010 18:33:59 +0000 Subject: - Fix some style(9) bugs Pointed out by: bde --- lib/libc/nls/msgcat.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/nls/msgcat.c b/lib/libc/nls/msgcat.c index 0809d8a..0b008ea 100644 --- a/lib/libc/nls/msgcat.c +++ b/lib/libc/nls/msgcat.c @@ -107,12 +107,12 @@ SLIST_HEAD(listhead, catentry) cache = nl_catd catopen(const char *name, int type) { - int spcleft, saverr; - char path[PATH_MAX]; - char *nlspath, *lang, *base, *cptr, *pathP, *tmpptr; - char *cptr1, *plang, *pter, *pcode; - struct stat sbuf; - struct catentry *np; + struct stat sbuf; + struct catentry *np; + char *base, *cptr, *cptr1, *lang, *nlspath, *pathP, *pcode; + char *plang, *pter, *tmpptr; + int saverr, spcleft; + char path[PATH_MAX]; if (name == NULL || *name == '\0') NLRETERR(EINVAL); @@ -247,10 +247,10 @@ catopen(const char *name, int type) char * catgets(nl_catd catd, int set_id, int msg_id, const char *s) { - struct _nls_cat_hdr *cat_hdr; - struct _nls_set_hdr *set_hdr; - struct _nls_msg_hdr *msg_hdr; - int l, u, i, r; + struct _nls_cat_hdr *cat_hdr; + struct _nls_msg_hdr *msg_hdr; + struct _nls_set_hdr *set_hdr; + int i, l, r, u; if (catd == NULL || catd == NLERR) { errno = EBADF; @@ -315,7 +315,7 @@ notfound: int catclose(nl_catd catd) { - struct catentry *np; + struct catentry *np; if (catd == NULL || catd == NLERR) { errno = EBADF; @@ -348,11 +348,11 @@ catclose(nl_catd catd) static nl_catd load_msgcat(const char *path, const char *name, const char *lang) { - struct stat st; - nl_catd catd; - struct catentry *np; - void *data; - int fd; + struct stat st; + nl_catd catd; + struct catentry *np; + void *data; + int fd; /* path/name will never be NULL here */ @@ -418,4 +418,3 @@ load_msgcat(const char *path, const char *name, const char *lang) UNLOCK; return (catd); } - -- cgit v1.1 From e48113132a62d511bbf3123991514b2cfd49f65a Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 31 Jan 2010 14:51:04 +0000 Subject: Perform some cleanups to devname(3). - Make sure the mode argument is either a character or a block device. - Use S_IS*() instead of checking S_IF*-flags by hand. - Don't use kern.devname when the argument is already NODEV. - Always call snprintf with the proper amount of arguments corresponding with the format. - Perform some whitespace fixes. Tabs instead of 4 spaces, missing space for return statement. - Remove unneeded includes. --- lib/libc/gen/devname.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/devname.c b/lib/libc/gen/devname.c index 21e46e6..65a690f 100644 --- a/lib/libc/gen/devname.c +++ b/lib/libc/gen/devname.c @@ -36,10 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include #include -#include #include #include #include @@ -49,22 +46,22 @@ devname_r(dev_t dev, mode_t type, char *buf, int len) { int i; size_t j; - char *r; - if ((type & S_IFMT) == S_IFCHR) { + if (dev == NODEV || !(S_ISCHR(type) || S_ISBLK(dev))) { + strlcpy(buf, "#NODEV", len); + return (buf); + } + + if (S_ISCHR(type)) { j = len; i = sysctlbyname("kern.devname", buf, &j, &dev, sizeof (dev)); if (i == 0) - return (buf); + return (buf); } /* Finally just format it */ - if (dev == NODEV) - r = "#NODEV"; - else - r = "#%c:%d:0x%x"; - snprintf(buf, len, r, - (type & S_IFMT) == S_IFCHR ? 'C' : 'B', major(dev), minor(dev)); + snprintf(buf, len, "#%c:%d:0x%x", + S_ISCHR(type) ? 'C' : 'B', major(dev), minor(dev)); return (buf); } @@ -73,5 +70,5 @@ devname(dev_t dev, mode_t type) { static char buf[SPECNAMELEN + 1]; - return(devname_r(dev, type, buf, sizeof(buf))); + return (devname_r(dev, type, buf, sizeof(buf))); } -- cgit v1.1 From b51b4f4d2bd4524c3a6383abffcde25ab26f3059 Mon Sep 17 00:00:00 2001 From: brucec Date: Sun, 31 Jan 2010 21:45:14 +0000 Subject: Fix typo of ENOTCONN. Add missing RETURN VALUES section in sctp_opt_info(3). Approved by: rrs (mentor) --- lib/libc/net/sctp_opt_info.3 | 2 ++ lib/libc/net/sctp_recvmsg.3 | 2 +- lib/libc/net/sctp_send.3 | 2 +- lib/libc/net/sctp_sendmsg.3 | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/net/sctp_opt_info.3 b/lib/libc/net/sctp_opt_info.3 index 581a220..f010613 100644 --- a/lib/libc/net/sctp_opt_info.3 +++ b/lib/libc/net/sctp_opt_info.3 @@ -87,6 +87,8 @@ socket options. .Dv SCTP_PEER_AUTH_CHUNKS .Pp .Dv SCTP_LOCAL_AUTH_CHUNKS +.Sh RETURN VALUES +The call returns 0 on success and -1 upon error. .Sh ERRORS The .Fn sctp_opt_info diff --git a/lib/libc/net/sctp_recvmsg.3 b/lib/libc/net/sctp_recvmsg.3 index f874880..a5926bf 100644 --- a/lib/libc/net/sctp_recvmsg.3 +++ b/lib/libc/net/sctp_recvmsg.3 @@ -269,7 +269,7 @@ This generally indicates that the interface has stopped sending, but may be caused by transient congestion. .It Bq Er EHOSTUNREACH The remote host was unreachable. -.It Bq Er ENOTCON +.It Bq Er ENOTCONN On a one-to-one style socket no association exists. .It Bq Er ECONNRESET An abort was received by the stack while the user was diff --git a/lib/libc/net/sctp_send.3 b/lib/libc/net/sctp_send.3 index dd96bcf..8a4142c 100644 --- a/lib/libc/net/sctp_send.3 +++ b/lib/libc/net/sctp_send.3 @@ -319,7 +319,7 @@ This generally indicates that the interface has stopped sending, but may be caused by transient congestion. .It Bq Er EHOSTUNREACH The remote host was unreachable. -.It Bq Er ENOTCON +.It Bq Er ENOTCONN On a one-to-one style socket no association exists. .It Bq Er ECONNRESET An abort was received by the stack while the user was diff --git a/lib/libc/net/sctp_sendmsg.3 b/lib/libc/net/sctp_sendmsg.3 index 525a87c..c54aaef 100644 --- a/lib/libc/net/sctp_sendmsg.3 +++ b/lib/libc/net/sctp_sendmsg.3 @@ -296,7 +296,7 @@ This generally indicates that the interface has stopped sending, but may be caused by transient congestion. .It Bq Er EHOSTUNREACH The remote host was unreachable. -.It Bq Er ENOTCON +.It Bq Er ENOTCONN On a one-to-one style socket no association exists. .It Bq Er ECONNRESET An abort was received by the stack while the user was -- cgit v1.1 From c801976d1315cbf2f0b443e7850c19bcda1cf5ce Mon Sep 17 00:00:00 2001 From: brucec Date: Sun, 31 Jan 2010 21:47:39 +0000 Subject: Remove extra semicolon. Approved by: rrs (mentor) --- lib/libc/net/sctp_sys_calls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/net/sctp_sys_calls.c b/lib/libc/net/sctp_sys_calls.c index 715fcbd..d876293 100644 --- a/lib/libc/net/sctp_sys_calls.c +++ b/lib/libc/net/sctp_sys_calls.c @@ -784,7 +784,7 @@ sctp_sendx(int sd, const void *msg, size_t msg_len, free(buf); if (ret != 0) { if (errno == EALREADY) { - no_end_cx = 1;; + no_end_cx = 1; goto continue_send; } return (ret); -- cgit v1.1 From 1c0068af90820bd887ab3dde5f948d2036c15dcf Mon Sep 17 00:00:00 2001 From: jasone Date: Sun, 31 Jan 2010 23:16:10 +0000 Subject: Fix bugs: * Fix a race in chunk_dealloc_dss(). * Check for allocation failure before zeroing memory in base_calloc(). Merge enhancements from a divergent version of jemalloc: * Convert thread-specific caching from magazines to an algorithm that is more tunable, and implement incremental GC. * Add support for medium size classes, [4KiB..32KiB], 2KiB apart by default. * Add dirty page tracking for pages within active small/medium object runs. This allows malloc to track precisely which pages are in active use, which makes dirty page purging more effective. * Base maximum dirty page count on proportion of active memory. * Use optional zeroing in arena_chunk_alloc() to avoid needless zeroing of chunks. This is useful in the context of DSS allocation, since a long-lived application may commonly recycle chunks. * Increase the default chunk size from 1MiB to 4MiB. Remove feature: * Remove the dynamic rebalancing code, since thread caching reduces its utility. --- lib/libc/stdlib/malloc.3 | 148 ++- lib/libc/stdlib/malloc.c | 3246 ++++++++++++++++++++++++++++------------------ lib/libc/stdlib/ql.h | 122 ++ lib/libc/stdlib/qr.h | 106 ++ 4 files changed, 2263 insertions(+), 1359 deletions(-) create mode 100644 lib/libc/stdlib/ql.h create mode 100644 lib/libc/stdlib/qr.h (limited to 'lib/libc') diff --git a/lib/libc/stdlib/malloc.3 b/lib/libc/stdlib/malloc.3 index 308ba7b..9b9fe96 100644 --- a/lib/libc/stdlib/malloc.3 +++ b/lib/libc/stdlib/malloc.3 @@ -32,7 +32,7 @@ .\" @(#)malloc.3 8.1 (Berkeley) 6/4/93 .\" $FreeBSD$ .\" -.Dd September 26, 2009 +.Dd January 31, 2010 .Dt MALLOC 3 .Os .Sh NAME @@ -55,9 +55,7 @@ .Ft const char * .Va _malloc_options ; .Ft void -.Fo \*(lp*_malloc_message\*(rp -.Fa "const char *p1" "const char *p2" "const char *p3" "const char *p4" -.Fc +.Fn \*(lp*_malloc_message\*(rp "const char *p1" "const char *p2" "const char *p3" "const char *p4" .In malloc_np.h .Ft size_t .Fn malloc_usable_size "const void *ptr" @@ -124,7 +122,9 @@ will free the passed pointer when the requested memory cannot be allocated. This is a .Fx specific API designed to ease the problems with traditional coding styles -for realloc causing memory leaks in libraries. +for +.Fn realloc +causing memory leaks in libraries. .Pp The .Fn free @@ -184,18 +184,6 @@ flags being set) become fatal. The process will call .Xr abort 3 in these cases. -.It B -Double/halve the per-arena lock contention threshold at which a thread is -randomly re-assigned to an arena. -This dynamic load balancing tends to push threads away from highly contended -arenas, which avoids worst case contention scenarios in which threads -disproportionately utilize arenas. -However, due to the highly dynamic load that applications may place on the -allocator, it is impossible for the allocator to know in advance how sensitive -it should be to contention over arenas. -Therefore, some applications may benefit from increasing or decreasing this -threshold parameter. -This option is not available for some configurations (non-PIC). .It C Double/halve the size of the maximum size class that is a multiple of the cacheline size (64). @@ -209,44 +197,62 @@ This option is enabled by default. See the .Dq M option for related information and interactions. +.It E +Double/halve the size of the maximum medium size class. +The valid range is from one page to one half chunk. +The default value is 32 KiB. .It F -Double/halve the per-arena maximum number of dirty unused pages that are -allowed to accumulate before informing the kernel about at least half of those -pages via +Halve/double the per-arena minimum ratio of active to dirty pages. +Some dirty unused pages may be allowed to accumulate, within the limit set by +the ratio, before informing the kernel about at least half of those pages via .Xr madvise 2 . This provides the kernel with sufficient information to recycle dirty pages if physical memory becomes scarce and the pages remain unused. -The default is 512 pages per arena; -.Ev MALLOC_OPTIONS=10f -will prevent any dirty unused pages from accumulating. +The default minimum ratio is 32:1; +.Ev MALLOC_OPTIONS=6F +will disable dirty page purging. .It G -When there are multiple threads, use thread-specific caching for objects that -are smaller than one page. -This option is enabled by default. -Thread-specific caching allows many allocations to be satisfied without -performing any thread synchronization, at the cost of increased memory use. +Double/halve the approximate interval (counted in terms of +thread-specific cache allocation/deallocation events) between full +thread-specific cache garbage collection sweeps. +Garbage collection is actually performed incrementally, one size +class at a time, in order to avoid large collection pauses. +The default sweep interval is 8192; +.Ev JEMALLOC_OPTIONS=14g +will disable garbage collection. +.It H +Double/halve the number of thread-specific cache slots per size +class. +When there are multiple threads, each thread uses a +thread-specific cache for small and medium objects. +Thread-specific caching allows many allocations to be satisfied +without performing any thread synchronization, at the cost of +increased memory use. See the -.Dq R +.Dq G option for related tuning information. -This option is not available for some configurations (non-PIC). +The default number of cache slots is 128; +.Ev JEMALLOC_OPTIONS=7h +will disable thread-specific caching. +Note that one cache slot per size class is not a valid +configuration due to implementation details. .It J Each byte of new memory allocated by .Fn malloc , -.Fn realloc +.Fn realloc , or .Fn reallocf will be initialized to 0xa5. All memory returned by .Fn free , -.Fn realloc +.Fn realloc , or .Fn reallocf will be initialized to 0x5a. This is intended for debugging and will impact performance negatively. .It K Double/halve the virtual memory chunk size. -The default chunk size is the maximum of 1 MB and the largest -page size that is less than or equal to 4 MB. +The default chunk size is 4 MiB. .It M Use .Xr mmap 2 @@ -279,14 +285,6 @@ Double/halve the size of the maximum size class that is a multiple of the quantum (8 or 16 bytes, depending on architecture). Above this size, cacheline spacing is used for size classes. The default value is 128 bytes. -.It R -Double/halve magazine size, which approximately doubles/halves the number of -rounds in each magazine. -Magazines are used by the thread-specific caching machinery to acquire and -release objects in bulk. -Increasing the magazine size decreases locking overhead, at the expense of -increased memory usage. -This option is not available for some configurations (non-PIC). .It U Generate .Dq utrace @@ -297,8 +295,7 @@ Consult the source for details on this option. .It V Attempting to allocate zero bytes will return a .Dv NULL -pointer instead of -a valid pointer. +pointer instead of a valid pointer. (The default behavior is to make a minimal allocation and return a pointer to it.) This option is provided for System V compatibility. @@ -306,21 +303,20 @@ This option is incompatible with the .Dq X option. .It X -Rather than return failure for any allocation function, -display a diagnostic message on -.Dv stderr -and cause the program to drop -core (using +Rather than return failure for any allocation function, display a diagnostic +message on +.Dv STDERR_FILENO +and cause the program to drop core (using .Xr abort 3 ) . -This option should be set at compile time by including the following in -the source code: +This option should be set at compile time by including the following in the +source code: .Bd -literal -offset indent _malloc_options = "X"; .Ed .It Z Each byte of new memory allocated by .Fn malloc , -.Fn realloc +.Fn realloc , or .Fn reallocf will be initialized to 0. @@ -378,9 +374,9 @@ improve performance, mainly due to reduced cache performance. However, it may make sense to reduce the number of arenas if an application does not make much use of the allocation functions. .Pp -In addition to multiple arenas, this allocator supports thread-specific -caching for small objects (smaller than one page), in order to make it -possible to completely avoid synchronization for most small allocation requests. +In addition to multiple arenas, this allocator supports thread-specific caching +for small and medium objects, in order to make it possible to completely avoid +synchronization for most small and medium allocation requests. Such caching allows very fast allocation in the common case, but it increases memory usage and fragmentation, since a bounded number of objects can remain allocated in each thread cache. @@ -391,23 +387,27 @@ Chunks are always aligned to multiples of the chunk size. This alignment makes it possible to find metadata for user objects very quickly. .Pp -User objects are broken into three categories according to size: small, large, -and huge. +User objects are broken into four categories according to size: small, medium, +large, and huge. Small objects are smaller than one page. +Medium objects range from one page to an upper limit determined at run time (see +the +.Dq E +option). Large objects are smaller than the chunk size. Huge objects are a multiple of the chunk size. -Small and large objects are managed by arenas; huge objects are managed +Small, medium, and large objects are managed by arenas; huge objects are managed separately in a single data structure that is shared by all threads. Huge objects are used by applications infrequently enough that this single data structure is not a scalability issue. .Pp Each chunk that is managed by an arena tracks its contents as runs of -contiguous pages (unused, backing a set of small objects, or backing one large -object). +contiguous pages (unused, backing a set of small or medium objects, or backing +one large object). The combination of chunk alignment and chunk page maps makes it possible to determine all metadata regarding small and large allocations in constant time. .Pp -Small objects are managed in groups by page runs. +Small and medium objects are managed in groups by page runs. Each run maintains a bitmap that tracks which regions are in use. Allocation requests that are no more than half the quantum (8 or 16, depending on architecture) are rounded up to the nearest power of two. @@ -419,10 +419,17 @@ Allocation requests that are more than the minumum cacheline-multiple size class, but no more than the minimum subpage-multiple size class (see the .Dq C option) are rounded up to the nearest multiple of the cacheline size (64). -Allocation requests that are more than the minimum subpage-multiple size class -are rounded up to the nearest multiple of the subpage size (256). -Allocation requests that are more than one page, but small enough to fit in -an arena-managed chunk (see the +Allocation requests that are more than the minimum subpage-multiple size class, +but no more than the maximum subpage-multiple size class are rounded up to the +nearest multiple of the subpage size (256). +Allocation requests that are more than the maximum subpage-multiple size class, +but no more than the maximum medium size class (see the +.Dq M +option) are rounded up to the nearest medium size class; spacing is an +automatically determined power of two and ranges from the subpage size to the +page size. +Allocation requests that are more than the maximum medium size class, but small +enough to fit in an arena-managed chunk (see the .Dq K option), are rounded up to the nearest run size. Allocation requests that are too large to fit in an arena-managed chunk are @@ -480,13 +487,12 @@ option is set, all warnings are treated as errors. .Pp The .Va _malloc_message -variable allows the programmer to override the function which emits -the text strings forming the errors and warnings if for some reason -the -.Dv stderr +variable allows the programmer to override the function which emits the text +strings forming the errors and warnings if for some reason the +.Dv STDERR_FILENO file descriptor is not suitable for this. -Please note that doing anything which tries to allocate memory in -this function is likely to result in a crash or deadlock. +Please note that doing anything which tries to allocate memory in this function +is likely to result in a crash or deadlock. .Pp All messages are prefixed by .Dq Ao Ar progname Ac Ns Li : (malloc) . diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c index bf862e2..f91220e 100644 --- a/lib/libc/stdlib/malloc.c +++ b/lib/libc/stdlib/malloc.c @@ -1,5 +1,5 @@ /*- - * Copyright (C) 2006-2008 Jason Evans . + * Copyright (C) 2006-2010 Jason Evans . * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -47,58 +47,67 @@ * * Allocation requests are rounded up to the nearest size class, and no record * of the original request size is maintained. Allocations are broken into - * categories according to size class. Assuming runtime defaults, 4 kB pages + * categories according to size class. Assuming runtime defaults, 4 KiB pages * and a 16 byte quantum on a 32-bit system, the size classes in each category * are as follows: * - * |=======================================| - * | Category | Subcategory | Size | - * |=======================================| - * | Small | Tiny | 2 | - * | | | 4 | - * | | | 8 | - * | |------------------+---------| - * | | Quantum-spaced | 16 | - * | | | 32 | - * | | | 48 | - * | | | ... | - * | | | 96 | - * | | | 112 | - * | | | 128 | - * | |------------------+---------| - * | | Cacheline-spaced | 192 | - * | | | 256 | - * | | | 320 | - * | | | 384 | - * | | | 448 | - * | | | 512 | - * | |------------------+---------| - * | | Sub-page | 760 | - * | | | 1024 | - * | | | 1280 | - * | | | ... | - * | | | 3328 | - * | | | 3584 | - * | | | 3840 | - * |=======================================| - * | Large | 4 kB | - * | | 8 kB | - * | | 12 kB | - * | | ... | - * | | 1012 kB | - * | | 1016 kB | - * | | 1020 kB | - * |=======================================| - * | Huge | 1 MB | - * | | 2 MB | - * | | 3 MB | - * | | ... | - * |=======================================| + * |========================================| + * | Category | Subcategory | Size | + * |========================================| + * | Small | Tiny | 2 | + * | | | 4 | + * | | | 8 | + * | |------------------+----------| + * | | Quantum-spaced | 16 | + * | | | 32 | + * | | | 48 | + * | | | ... | + * | | | 96 | + * | | | 112 | + * | | | 128 | + * | |------------------+----------| + * | | Cacheline-spaced | 192 | + * | | | 256 | + * | | | 320 | + * | | | 384 | + * | | | 448 | + * | | | 512 | + * | |------------------+----------| + * | | Sub-page | 760 | + * | | | 1024 | + * | | | 1280 | + * | | | ... | + * | | | 3328 | + * | | | 3584 | + * | | | 3840 | + * |========================================| + * | Medium | 4 KiB | + * | | 6 KiB | + * | | 8 KiB | + * | | ... | + * | | 28 KiB | + * | | 30 KiB | + * | | 32 KiB | + * |========================================| + * | Large | 36 KiB | + * | | 40 KiB | + * | | 44 KiB | + * | | ... | + * | | 1012 KiB | + * | | 1016 KiB | + * | | 1020 KiB | + * |========================================| + * | Huge | 1 MiB | + * | | 2 MiB | + * | | 3 MiB | + * | | ... | + * |========================================| * - * A different mechanism is used for each category: + * Different mechanisms are used accoding to category: * - * Small : Each size class is segregated into its own set of runs. Each run - * maintains a bitmap of which regions are free/allocated. + * Small/medium : Each size class is segregated into its own set of runs. + * Each run maintains a bitmap of which regions are + * free/allocated. * * Large : Each allocation is backed by a dedicated run. Metadata are stored * in the associated arena chunk header maps. @@ -134,18 +143,11 @@ #define MALLOC_TINY /* - * MALLOC_MAG enables a magazine-based thread-specific caching layer for small + * MALLOC_TCACHE enables a thread-specific caching layer for small and medium * objects. This makes it possible to allocate/deallocate objects without any * locking when the cache is in the steady state. */ -#define MALLOC_MAG - -/* - * MALLOC_BALANCE enables monitoring of arena lock contention and dynamically - * re-balances arena load if exponentially averaged contention exceeds a - * certain threshold. - */ -#define MALLOC_BALANCE +#define MALLOC_TCACHE /* * MALLOC_DSS enables use of sbrk(2) to allocate chunks from the data storage @@ -166,7 +168,6 @@ __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include -#include #include #include #include @@ -185,6 +186,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -192,18 +194,11 @@ __FBSDID("$FreeBSD$"); #include "un-namespace.h" -#ifdef MALLOC_DEBUG -# ifdef NDEBUG -# undef NDEBUG -# endif -#else -# ifndef NDEBUG -# define NDEBUG -# endif -#endif -#include - #include "rb.h" +#if (defined(MALLOC_TCACHE) && defined(MALLOC_STATS)) +#include "qr.h" +#include "ql.h" +#endif #ifdef MALLOC_DEBUG /* Disable inlining to make debugging easier. */ @@ -214,55 +209,57 @@ __FBSDID("$FreeBSD$"); #define STRERROR_BUF 64 /* - * Minimum alignment of allocations is 2^QUANTUM_2POW bytes. + * Minimum alignment of allocations is 2^LG_QUANTUM bytes. */ #ifdef __i386__ -# define QUANTUM_2POW 4 -# define SIZEOF_PTR_2POW 2 +# define LG_QUANTUM 4 +# define LG_SIZEOF_PTR 2 # define CPU_SPINWAIT __asm__ volatile("pause") #endif #ifdef __ia64__ -# define QUANTUM_2POW 4 -# define SIZEOF_PTR_2POW 3 +# define LG_QUANTUM 4 +# define LG_SIZEOF_PTR 3 #endif #ifdef __alpha__ -# define QUANTUM_2POW 4 -# define SIZEOF_PTR_2POW 3 +# define LG_QUANTUM 4 +# define LG_SIZEOF_PTR 3 # define NO_TLS #endif #ifdef __sparc64__ -# define QUANTUM_2POW 4 -# define SIZEOF_PTR_2POW 3 +# define LG_QUANTUM 4 +# define LG_SIZEOF_PTR 3 # define NO_TLS #endif #ifdef __amd64__ -# define QUANTUM_2POW 4 -# define SIZEOF_PTR_2POW 3 +# define LG_QUANTUM 4 +# define LG_SIZEOF_PTR 3 # define CPU_SPINWAIT __asm__ volatile("pause") #endif #ifdef __arm__ -# define QUANTUM_2POW 3 -# define SIZEOF_PTR_2POW 2 +# define LG_QUANTUM 3 +# define LG_SIZEOF_PTR 2 # define NO_TLS #endif #ifdef __mips__ -# define QUANTUM_2POW 3 -# define SIZEOF_PTR_2POW 2 +# define LG_QUANTUM 3 +# define LG_SIZEOF_PTR 2 # define NO_TLS #endif #ifdef __powerpc__ -# define QUANTUM_2POW 4 -# define SIZEOF_PTR_2POW 2 +# define LG_QUANTUM 4 +#endif +#ifdef __s390x__ +# define LG_QUANTUM 4 #endif -#define QUANTUM ((size_t)(1U << QUANTUM_2POW)) +#define QUANTUM ((size_t)(1U << LG_QUANTUM)) #define QUANTUM_MASK (QUANTUM - 1) -#define SIZEOF_PTR (1U << SIZEOF_PTR_2POW) +#define SIZEOF_PTR (1U << LG_SIZEOF_PTR) -/* sizeof(int) == (1U << SIZEOF_INT_2POW). */ -#ifndef SIZEOF_INT_2POW -# define SIZEOF_INT_2POW 2 +/* sizeof(int) == (1U << LG_SIZEOF_INT). */ +#ifndef LG_SIZEOF_INT +# define LG_SIZEOF_INT 2 #endif /* We can't use TLS in non-PIC programs, since TLS relies on loader magic. */ @@ -271,13 +268,9 @@ __FBSDID("$FreeBSD$"); #endif #ifdef NO_TLS - /* MALLOC_MAG requires TLS. */ -# ifdef MALLOC_MAG -# undef MALLOC_MAG -# endif - /* MALLOC_BALANCE requires TLS. */ -# ifdef MALLOC_BALANCE -# undef MALLOC_BALANCE + /* MALLOC_TCACHE requires TLS. */ +# ifdef MALLOC_TCACHE +# undef MALLOC_TCACHE # endif #endif @@ -285,17 +278,24 @@ __FBSDID("$FreeBSD$"); * Size and alignment of memory chunks that are allocated by the OS's virtual * memory system. */ -#define CHUNK_2POW_DEFAULT 20 +#define LG_CHUNK_DEFAULT 22 -/* Maximum number of dirty pages per arena. */ -#define DIRTY_MAX_DEFAULT (1U << 9) +/* + * The minimum ratio of active:dirty pages per arena is computed as: + * + * (nactive >> opt_lg_dirty_mult) >= ndirty + * + * So, supposing that opt_lg_dirty_mult is 5, there can be no less than 32 + * times as many active pages as dirty pages. + */ +#define LG_DIRTY_MULT_DEFAULT 5 /* * Maximum size of L1 cache line. This is used to avoid cache line aliasing. * In addition, this controls the spacing of cacheline-spaced size classes. */ -#define CACHELINE_2POW 6 -#define CACHELINE ((size_t)(1U << CACHELINE_2POW)) +#define LG_CACHELINE 6 +#define CACHELINE ((size_t)(1U << LG_CACHELINE)) #define CACHELINE_MASK (CACHELINE - 1) /* @@ -305,13 +305,13 @@ __FBSDID("$FreeBSD$"); * There must be at least 4 subpages per page, due to the way size classes are * handled. */ -#define SUBPAGE_2POW 8 -#define SUBPAGE ((size_t)(1U << SUBPAGE_2POW)) +#define LG_SUBPAGE 8 +#define SUBPAGE ((size_t)(1U << LG_SUBPAGE)) #define SUBPAGE_MASK (SUBPAGE - 1) #ifdef MALLOC_TINY /* Smallest size class to support. */ -# define TINY_MIN_2POW 1 +# define LG_TINY_MIN 1 #endif /* @@ -319,14 +319,20 @@ __FBSDID("$FreeBSD$"); * a power of 2. Above this size, allocations are rounded up to the nearest * power of 2. */ -#define QSPACE_MAX_2POW_DEFAULT 7 +#define LG_QSPACE_MAX_DEFAULT 7 /* * Maximum size class that is a multiple of the cacheline, but not (necessarily) * a power of 2. Above this size, allocations are rounded up to the nearest * power of 2. */ -#define CSPACE_MAX_2POW_DEFAULT 9 +#define LG_CSPACE_MAX_DEFAULT 9 + +/* + * Maximum medium size class. This must not be more than 1/4 of a chunk + * (LG_MEDIUM_MAX_DEFAULT <= LG_CHUNK_DEFAULT - 2). + */ +#define LG_MEDIUM_MAX_DEFAULT 15 /* * RUN_MAX_OVRHD indicates maximum desired run header overhead. Runs are sized @@ -350,7 +356,10 @@ __FBSDID("$FreeBSD$"); #define RUN_MAX_OVRHD_RELAX 0x00001800U /* Put a cap on small object run size. This overrides RUN_MAX_OVRHD. */ -#define RUN_MAX_SMALL (12 * PAGE_SIZE) +#define RUN_MAX_SMALL \ + (arena_maxclass <= (1U << (CHUNK_MAP_LG_PG_RANGE + PAGE_SHIFT)) \ + ? arena_maxclass : (1U << (CHUNK_MAP_LG_PG_RANGE + \ + PAGE_SHIFT))) /* * Hyper-threaded CPUs may need a special instruction inside spin loops in @@ -366,40 +375,21 @@ __FBSDID("$FreeBSD$"); * potential for priority inversion deadlock. Backing off past a certain point * can actually waste time. */ -#define SPIN_LIMIT_2POW 11 - -/* - * Conversion from spinning to blocking is expensive; we use (1U << - * BLOCK_COST_2POW) to estimate how many more times costly blocking is than - * worst-case spinning. - */ -#define BLOCK_COST_2POW 4 - -#ifdef MALLOC_MAG - /* - * Default magazine size, in bytes. max_rounds is calculated to make - * optimal use of the space, leaving just enough room for the magazine - * header. - */ -# define MAG_SIZE_2POW_DEFAULT 9 -#endif +#define LG_SPIN_LIMIT 11 -#ifdef MALLOC_BALANCE +#ifdef MALLOC_TCACHE /* - * We use an exponential moving average to track recent lock contention, - * where the size of the history window is N, and alpha=2/(N+1). - * - * Due to integer math rounding, very small values here can cause - * substantial degradation in accuracy, thus making the moving average decay - * faster than it would with precise calculation. + * Default number of cache slots for each bin in the thread cache (0: + * disabled). */ -# define BALANCE_ALPHA_INV_2POW 9 - +# define LG_TCACHE_NSLOTS_DEFAULT 7 /* - * Threshold value for the exponential moving contention average at which to - * re-assign a thread. + * (1U << opt_lg_tcache_gc_sweep) is the approximate number of + * allocation events between full GC sweeps (-1: disabled). Integer + * rounding may cause the actual number to be slightly higher, since GC is + * performed incrementally. */ -# define BALANCE_THRESHOLD_DEFAULT (1U << (SPIN_LIMIT_2POW-4)) +# define LG_TCACHE_GC_SWEEP_DEFAULT 13 #endif /******************************************************************************/ @@ -426,6 +416,17 @@ static malloc_mutex_t init_lock = {_SPINLOCK_INITIALIZER}; #ifdef MALLOC_STATS +#ifdef MALLOC_TCACHE +typedef struct tcache_bin_stats_s tcache_bin_stats_t; +struct tcache_bin_stats_s { + /* + * Number of allocation requests that corresponded to the size of this + * bin. + */ + uint64_t nrequests; +}; +#endif + typedef struct malloc_bin_stats_s malloc_bin_stats_t; struct malloc_bin_stats_s { /* @@ -434,9 +435,12 @@ struct malloc_bin_stats_s { */ uint64_t nrequests; -#ifdef MALLOC_MAG - /* Number of magazine reloads from this bin. */ - uint64_t nmags; +#ifdef MALLOC_TCACHE + /* Number of tcache fills from this bin. */ + uint64_t nfills; + + /* Number of tcache flushes to this bin. */ + uint64_t nflushes; #endif /* Total number of runs created for this bin's size class. */ @@ -449,10 +453,24 @@ struct malloc_bin_stats_s { uint64_t reruns; /* High-water mark for this bin. */ - unsigned long highruns; + size_t highruns; /* Current number of runs in this bin. */ - unsigned long curruns; + size_t curruns; +}; + +typedef struct malloc_large_stats_s malloc_large_stats_t; +struct malloc_large_stats_s { + /* + * Number of allocation requests that corresponded to this size class. + */ + uint64_t nrequests; + + /* High-water mark for this size class. */ + size_t highruns; + + /* Current number of runs of this size class. */ + size_t curruns; }; typedef struct arena_stats_s arena_stats_t; @@ -474,14 +492,21 @@ struct arena_stats_s { uint64_t nmalloc_small; uint64_t ndalloc_small; + size_t allocated_medium; + uint64_t nmalloc_medium; + uint64_t ndalloc_medium; + size_t allocated_large; uint64_t nmalloc_large; uint64_t ndalloc_large; -#ifdef MALLOC_BALANCE - /* Number of times this arena reassigned a thread due to contention. */ - uint64_t nbalance; -#endif + /* + * One element for each possible size class, including sizes that + * overlap with bin size classes. This is necessary because ipalloc() + * sometimes has to use such large objects in order to assure proper + * alignment. + */ + malloc_large_stats_t *lstats; }; typedef struct chunk_stats_s chunk_stats_t; @@ -490,14 +515,14 @@ struct chunk_stats_s { uint64_t nchunks; /* High-water mark for number of chunks allocated. */ - unsigned long highchunks; + size_t highchunks; /* * Current number of chunks allocated. This value isn't maintained for * any other purpose, so keep track of it in order to be able to set * highchunks. */ - unsigned long curchunks; + size_t curchunks; }; #endif /* #ifdef MALLOC_STATS */ @@ -550,14 +575,14 @@ struct arena_chunk_map_s { * Run address (or size) and various flags are stored together. The bit * layout looks like (assuming 32-bit system): * - * ???????? ???????? ????---- ---kdzla + * ???????? ???????? ????cccc ccccdzla * * ? : Unallocated: Run address for first/last pages, unset for internal * pages. - * Small: Run address. + * Small/medium: Don't care. * Large: Run size for first page, unset for trailing pages. * - : Unused. - * k : key? + * c : refcount (could overflow for PAGE_SIZE >= 128 KiB) * d : dirty? * z : zeroed? * l : large? @@ -565,7 +590,7 @@ struct arena_chunk_map_s { * * Following are example bit patterns for the three types of runs. * - * r : run address + * p : run page offset * s : run size * x : don't care * - : 0 @@ -576,10 +601,10 @@ struct arena_chunk_map_s { * xxxxxxxx xxxxxxxx xxxx---- ----d--- * ssssssss ssssssss ssss---- -----z-- * - * Small: - * rrrrrrrr rrrrrrrr rrrr---- -------a - * rrrrrrrr rrrrrrrr rrrr---- -------a - * rrrrrrrr rrrrrrrr rrrr---- -------a + * Small/medium: + * pppppppp ppppcccc cccccccc cccc---a + * pppppppp ppppcccc cccccccc cccc---a + * pppppppp ppppcccc cccccccc cccc---a * * Large: * ssssssss ssssssss ssss---- ------la @@ -587,11 +612,19 @@ struct arena_chunk_map_s { * -------- -------- -------- ------la */ size_t bits; -#define CHUNK_MAP_KEY ((size_t)0x10U) -#define CHUNK_MAP_DIRTY ((size_t)0x08U) -#define CHUNK_MAP_ZEROED ((size_t)0x04U) -#define CHUNK_MAP_LARGE ((size_t)0x02U) -#define CHUNK_MAP_ALLOCATED ((size_t)0x01U) +#define CHUNK_MAP_PG_MASK ((size_t)0xfff00000U) +#define CHUNK_MAP_PG_SHIFT 20 +#define CHUNK_MAP_LG_PG_RANGE 12 + +#define CHUNK_MAP_RC_MASK ((size_t)0xffff0U) +#define CHUNK_MAP_RC_ONE ((size_t)0x00010U) + +#define CHUNK_MAP_FLAGS_MASK ((size_t)0xfU) +#define CHUNK_MAP_DIRTY ((size_t)0x8U) +#define CHUNK_MAP_ZEROED ((size_t)0x4U) +#define CHUNK_MAP_LARGE ((size_t)0x2U) +#define CHUNK_MAP_ALLOCATED ((size_t)0x1U) +#define CHUNK_MAP_KEY (CHUNK_MAP_DIRTY | CHUNK_MAP_ALLOCATED) }; typedef rb_tree(arena_chunk_map_t) arena_avail_tree_t; typedef rb_tree(arena_chunk_map_t) arena_run_tree_t; @@ -605,6 +638,13 @@ struct arena_chunk_s { /* Linkage for the arena's chunks_dirty tree. */ rb_node(arena_chunk_t) link_dirty; + /* + * True if the chunk is currently in the chunks_dirty tree, due to + * having at some point contained one or more dirty pages. Removal + * from chunks_dirty is lazy, so (dirtied && ndirty == 0) is possible. + */ + bool dirtied; + /* Number of dirty pages. */ size_t ndirty; @@ -670,6 +710,10 @@ struct arena_bin_s { #endif }; +#ifdef MALLOC_TCACHE +typedef struct tcache_s tcache_t; +#endif + struct arena_s { #ifdef MALLOC_DEBUG uint32_t magic; @@ -681,6 +725,13 @@ struct arena_s { #ifdef MALLOC_STATS arena_stats_t stats; +# ifdef MALLOC_TCACHE + /* + * List of tcaches for extant threads associated with this arena. + * Stats from these are merged incrementally, and at exit. + */ + ql_head(tcache_t) tcache_ql; +# endif #endif /* Tree of dirty-page-containing chunks this arena manages. */ @@ -698,6 +749,9 @@ struct arena_s { */ arena_chunk_t *spare; + /* Number of pages in active runs. */ + size_t nactive; + /* * Current count of pages within unused runs that are potentially * dirty, and for which madvise(... MADV_FREE) has not been called. By @@ -712,67 +766,77 @@ struct arena_s { */ arena_avail_tree_t runs_avail; -#ifdef MALLOC_BALANCE /* - * The arena load balancing machinery needs to keep track of how much - * lock contention there is. This value is exponentially averaged. - */ - uint32_t contention; -#endif - - /* - * bins is used to store rings of free regions of the following sizes, - * assuming a 16-byte quantum, 4kB page size, and default + * bins is used to store trees of free regions of the following sizes, + * assuming a 16-byte quantum, 4 KiB page size, and default * MALLOC_OPTIONS. * - * bins[i] | size | - * --------+------+ - * 0 | 2 | - * 1 | 4 | - * 2 | 8 | - * --------+------+ - * 3 | 16 | - * 4 | 32 | - * 5 | 48 | - * 6 | 64 | - * : : - * : : - * 33 | 496 | - * 34 | 512 | - * --------+------+ - * 35 | 1024 | - * 36 | 2048 | - * --------+------+ + * bins[i] | size | + * --------+--------+ + * 0 | 2 | + * 1 | 4 | + * 2 | 8 | + * --------+--------+ + * 3 | 16 | + * 4 | 32 | + * 5 | 48 | + * : : + * 8 | 96 | + * 9 | 112 | + * 10 | 128 | + * --------+--------+ + * 11 | 192 | + * 12 | 256 | + * 13 | 320 | + * 14 | 384 | + * 15 | 448 | + * 16 | 512 | + * --------+--------+ + * 17 | 768 | + * 18 | 1024 | + * 19 | 1280 | + * : : + * 27 | 3328 | + * 28 | 3584 | + * 29 | 3840 | + * --------+--------+ + * 30 | 4 KiB | + * 31 | 6 KiB | + * 33 | 8 KiB | + * : : + * 43 | 28 KiB | + * 44 | 30 KiB | + * 45 | 32 KiB | + * --------+--------+ */ arena_bin_t bins[1]; /* Dynamically sized. */ }; /******************************************************************************/ /* - * Magazine data structures. + * Thread cache data structures. */ -#ifdef MALLOC_MAG -typedef struct mag_s mag_t; -struct mag_s { - size_t binind; /* Index of associated bin. */ - size_t nrounds; - void *rounds[1]; /* Dynamically sized. */ -}; - -/* - * Magazines are lazily allocated, but once created, they remain until the - * associated mag_rack is destroyed. - */ -typedef struct bin_mags_s bin_mags_t; -struct bin_mags_s { - mag_t *curmag; - mag_t *sparemag; +#ifdef MALLOC_TCACHE +typedef struct tcache_bin_s tcache_bin_t; +struct tcache_bin_s { +# ifdef MALLOC_STATS + tcache_bin_stats_t tstats; +# endif + unsigned low_water; /* Min # cached since last GC. */ + unsigned high_water; /* Max # cached since last GC. */ + unsigned ncached; /* # of cached objects. */ + void *slots[1]; /* Dynamically sized. */ }; -typedef struct mag_rack_s mag_rack_t; -struct mag_rack_s { - bin_mags_t bin_mags[1]; /* Dynamically sized. */ +struct tcache_s { +# ifdef MALLOC_STATS + ql_elm(tcache_t) link; /* Used for aggregating stats. */ +# endif + arena_t *arena; /* This thread's arena. */ + unsigned ev_cnt; /* Event count since incremental GC. */ + unsigned next_gc_bin; /* Next bin to GC. */ + tcache_bin_t *tbins[1]; /* Dynamically sized. */ }; #endif @@ -786,14 +850,16 @@ static unsigned ncpus; /* Various bin-related settings. */ #ifdef MALLOC_TINY /* Number of (2^n)-spaced tiny bins. */ -# define ntbins ((unsigned)(QUANTUM_2POW - TINY_MIN_2POW)) +# define ntbins ((unsigned)(LG_QUANTUM - LG_TINY_MIN)) #else # define ntbins 0 #endif static unsigned nqbins; /* Number of quantum-spaced bins. */ static unsigned ncbins; /* Number of cacheline-spaced bins. */ static unsigned nsbins; /* Number of subpage-spaced bins. */ +static unsigned nmbins; /* Number of medium bins. */ static unsigned nbins; +static unsigned mbin0; /* mbin offset (nbins - nmbins). */ #ifdef MALLOC_TINY # define tspace_max ((size_t)(QUANTUM >> 1)) #endif @@ -803,13 +869,26 @@ static size_t cspace_min; static size_t cspace_max; static size_t sspace_min; static size_t sspace_max; -#define bin_maxclass sspace_max +#define small_maxclass sspace_max +#define medium_min PAGE_SIZE +static size_t medium_max; +#define bin_maxclass medium_max + +/* + * Soft limit on the number of medium size classes. Spacing between medium + * size classes never exceeds pagesize, which can force more than NBINS_MAX + * medium size classes. + */ +#define NMBINS_MAX 16 +/* Spacing between medium size classes. */ +static size_t lg_mspace; +static size_t mspace_mask; -static uint8_t const *size2bin; +static uint8_t const *small_size2bin; /* - * const_size2bin is a static constant lookup table that in the common case can - * be used as-is for size2bin. For dynamically linked programs, this avoids - * a page of memory overhead per process. + * const_small_size2bin is a static constant lookup table that in the common + * case can be used as-is for small_size2bin. For dynamically linked programs, + * this avoids a page of memory overhead per process. */ #define S2B_1(i) i, #define S2B_2(i) S2B_1(i) S2B_1(i) @@ -820,9 +899,9 @@ static uint8_t const *size2bin; #define S2B_64(i) S2B_32(i) S2B_32(i) #define S2B_128(i) S2B_64(i) S2B_64(i) #define S2B_256(i) S2B_128(i) S2B_128(i) -static const uint8_t const_size2bin[PAGE_SIZE - 255] = { +static const uint8_t const_small_size2bin[PAGE_SIZE - 255] = { S2B_1(0xffU) /* 0 */ -#if (QUANTUM_2POW == 4) +#if (LG_QUANTUM == 4) /* 64-bit system ************************/ # ifdef MALLOC_TINY S2B_2(0) /* 2 */ @@ -923,10 +1002,6 @@ static const uint8_t const_size2bin[PAGE_SIZE - 255] = { #undef S2B_CMIN #undef S2B_SMIN -#ifdef MALLOC_MAG -static size_t max_rounds; -#endif - /* Various chunk-related settings. */ static size_t chunksize; static size_t chunksize_mask; /* (chunksize - 1). */ @@ -1006,31 +1081,51 @@ static size_t base_mapped; static arena_t **arenas; static unsigned narenas; #ifndef NO_TLS -# ifdef MALLOC_BALANCE -static unsigned narenas_2pow; -# else static unsigned next_arena; -# endif #endif static pthread_mutex_t arenas_lock; /* Protects arenas initialization. */ #ifndef NO_TLS /* - * Map of pthread_self() --> arenas[???], used for selecting an arena to use + * Map of _pthread_self() --> arenas[???], used for selecting an arena to use * for allocations. */ -static __thread arena_t *arenas_map; +static __thread arena_t *arenas_map + __attribute__((tls_model("initial-exec"))); #endif -#ifdef MALLOC_MAG +#ifdef MALLOC_TCACHE +/* Map of thread-specific caches. */ +static __thread tcache_t *tcache_tls + __attribute__((tls_model("initial-exec"))); + /* - * Map of thread-specific magazine racks, used for thread-specific object - * caching. + * Number of cache slots for each bin in the thread cache, or 0 if tcache is + * disabled. */ -static __thread mag_rack_t *mag_rack; +size_t tcache_nslots; + +/* Number of tcache allocation/deallocation events between incremental GCs. */ +unsigned tcache_gc_incr; #endif +/* + * Used by chunk_alloc_mmap() to decide whether to attempt the fast path and + * potentially avoid some system calls. We can get away without TLS here, + * since the state of mmap_unaligned only affects performance, rather than + * correct function. + */ +static +#ifndef NO_TLS + __thread +#endif + bool mmap_unaligned +#ifndef NO_TLS + __attribute__((tls_model("initial-exec"))) +#endif + ; #ifdef MALLOC_STATS +static malloc_mutex_t chunks_mtx; /* Chunk statistics. */ static chunk_stats_t stats_chunks; #endif @@ -1048,22 +1143,20 @@ static bool opt_junk = true; static bool opt_abort = false; static bool opt_junk = false; #endif +#ifdef MALLOC_TCACHE +static size_t opt_lg_tcache_nslots = LG_TCACHE_NSLOTS_DEFAULT; +static ssize_t opt_lg_tcache_gc_sweep = LG_TCACHE_GC_SWEEP_DEFAULT; +#endif #ifdef MALLOC_DSS static bool opt_dss = true; static bool opt_mmap = true; #endif -#ifdef MALLOC_MAG -static bool opt_mag = true; -static size_t opt_mag_size_2pow = MAG_SIZE_2POW_DEFAULT; -#endif -static size_t opt_dirty_max = DIRTY_MAX_DEFAULT; -#ifdef MALLOC_BALANCE -static uint64_t opt_balance_threshold = BALANCE_THRESHOLD_DEFAULT; -#endif -static bool opt_print_stats = false; -static size_t opt_qspace_max_2pow = QSPACE_MAX_2POW_DEFAULT; -static size_t opt_cspace_max_2pow = CSPACE_MAX_2POW_DEFAULT; -static size_t opt_chunk_2pow = CHUNK_2POW_DEFAULT; +static ssize_t opt_lg_dirty_mult = LG_DIRTY_MULT_DEFAULT; +static bool opt_stats_print = false; +static size_t opt_lg_qspace_max = LG_QSPACE_MAX_DEFAULT; +static size_t opt_lg_cspace_max = LG_CSPACE_MAX_DEFAULT; +static size_t opt_lg_medium_max = LG_MEDIUM_MAX_DEFAULT; +static size_t opt_lg_chunk = LG_CHUNK_DEFAULT; static bool opt_utrace = false; static bool opt_sysv = false; static bool opt_xmalloc = false; @@ -1092,12 +1185,15 @@ typedef struct { static void malloc_mutex_init(malloc_mutex_t *mutex); static bool malloc_spin_init(pthread_mutex_t *lock); +#ifdef MALLOC_TINY +static size_t pow2_ceil(size_t x); +#endif static void wrtmessage(const char *p1, const char *p2, const char *p3, const char *p4); #ifdef MALLOC_STATS static void malloc_printf(const char *format, ...); #endif -static char *umax2s(uintmax_t x, char *s); +static char *umax2s(uintmax_t x, unsigned base, char *s); #ifdef MALLOC_DSS static bool base_pages_alloc_dss(size_t minsize); #endif @@ -1107,17 +1203,15 @@ static void *base_alloc(size_t size); static void *base_calloc(size_t number, size_t size); static extent_node_t *base_node_alloc(void); static void base_node_dealloc(extent_node_t *node); -#ifdef MALLOC_STATS -static void stats_print(arena_t *arena); -#endif static void *pages_map(void *addr, size_t size); static void pages_unmap(void *addr, size_t size); #ifdef MALLOC_DSS -static void *chunk_alloc_dss(size_t size); -static void *chunk_recycle_dss(size_t size, bool zero); +static void *chunk_alloc_dss(size_t size, bool *zero); +static void *chunk_recycle_dss(size_t size, bool *zero); #endif +static void *chunk_alloc_mmap_slow(size_t size, bool unaligned); static void *chunk_alloc_mmap(size_t size); -static void *chunk_alloc(size_t size, bool zero); +static void *chunk_alloc(size_t size, bool *zero); #ifdef MALLOC_DSS static extent_node_t *chunk_dealloc_dss_record(void *chunk, size_t size); static bool chunk_dealloc_dss(void *chunk, size_t size); @@ -1142,51 +1236,163 @@ static void arena_run_trim_tail(arena_t *arena, arena_chunk_t *chunk, static arena_run_t *arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin); static void *arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin); static size_t arena_bin_run_size_calc(arena_bin_t *bin, size_t min_run_size); -#ifdef MALLOC_BALANCE -static void arena_lock_balance_hard(arena_t *arena); -#endif -#ifdef MALLOC_MAG -static void mag_load(mag_t *mag); +#ifdef MALLOC_TCACHE +static void tcache_bin_fill(tcache_t *tcache, tcache_bin_t *tbin, + size_t binind); +static void *tcache_alloc_hard(tcache_t *tcache, tcache_bin_t *tbin, + size_t binind); #endif +static void *arena_malloc_medium(arena_t *arena, size_t size, bool zero); static void *arena_malloc_large(arena_t *arena, size_t size, bool zero); static void *arena_palloc(arena_t *arena, size_t alignment, size_t size, size_t alloc_size); +static bool arena_is_large(const void *ptr); static size_t arena_salloc(const void *ptr); -#ifdef MALLOC_MAG -static void mag_unload(mag_t *mag); +static void +arena_dalloc_bin_run(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run, + arena_bin_t *bin); +#ifdef MALLOC_STATS +static void arena_stats_print(arena_t *arena); +#endif +static void stats_print_atexit(void); +#ifdef MALLOC_TCACHE +static void tcache_bin_flush(tcache_bin_t *tbin, size_t binind, + unsigned rem); #endif static void arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk, void *ptr); +#ifdef MALLOC_TCACHE +static void arena_dalloc_hard(arena_t *arena, arena_chunk_t *chunk, + void *ptr, arena_chunk_map_t *mapelm, tcache_t *tcache); +#endif static void arena_ralloc_large_shrink(arena_t *arena, arena_chunk_t *chunk, void *ptr, size_t size, size_t oldsize); static bool arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr, size_t size, size_t oldsize); static bool arena_ralloc_large(void *ptr, size_t size, size_t oldsize); static void *arena_ralloc(void *ptr, size_t size, size_t oldsize); -static bool arena_new(arena_t *arena); +static bool arena_new(arena_t *arena, unsigned ind); static arena_t *arenas_extend(unsigned ind); -#ifdef MALLOC_MAG -static mag_t *mag_create(arena_t *arena, size_t binind); -static void mag_destroy(mag_t *mag); -static mag_rack_t *mag_rack_create(arena_t *arena); -static void mag_rack_destroy(mag_rack_t *rack); +#ifdef MALLOC_TCACHE +static tcache_bin_t *tcache_bin_create(arena_t *arena); +static void tcache_bin_destroy(tcache_t *tcache, tcache_bin_t *tbin, + unsigned binind); +# ifdef MALLOC_STATS +static void tcache_stats_merge(tcache_t *tcache, arena_t *arena); +# endif +static tcache_t *tcache_create(arena_t *arena); +static void tcache_destroy(tcache_t *tcache); #endif static void *huge_malloc(size_t size, bool zero); static void *huge_palloc(size_t alignment, size_t size); static void *huge_ralloc(void *ptr, size_t size, size_t oldsize); static void huge_dalloc(void *ptr); -static void malloc_print_stats(void); +static void malloc_stats_print(void); #ifdef MALLOC_DEBUG -static void size2bin_validate(void); +static void small_size2bin_validate(void); #endif -static bool size2bin_init(void); -static bool size2bin_init_hard(void); +static bool small_size2bin_init(void); +static bool small_size2bin_init_hard(void); +static unsigned malloc_ncpus(void); static bool malloc_init_hard(void); /* * End function prototypes. */ /******************************************************************************/ + +static void +wrtmessage(const char *p1, const char *p2, const char *p3, const char *p4) +{ + + if (_write(STDERR_FILENO, p1, strlen(p1)) < 0 + || _write(STDERR_FILENO, p2, strlen(p2)) < 0 + || _write(STDERR_FILENO, p3, strlen(p3)) < 0 + || _write(STDERR_FILENO, p4, strlen(p4)) < 0) + return; +} + +void (*_malloc_message)(const char *p1, const char *p2, const char *p3, + const char *p4) = wrtmessage; + +/* + * We don't want to depend on vsnprintf() for production builds, since that can + * cause unnecessary bloat for static binaries. umax2s() provides minimal + * integer printing functionality, so that malloc_printf() use can be limited to + * MALLOC_STATS code. + */ +#define UMAX2S_BUFSIZE 65 +static char * +umax2s(uintmax_t x, unsigned base, char *s) +{ + unsigned i; + + i = UMAX2S_BUFSIZE - 1; + s[i] = '\0'; + switch (base) { + case 10: + do { + i--; + s[i] = "0123456789"[x % 10]; + x /= 10; + } while (x > 0); + break; + case 16: + do { + i--; + s[i] = "0123456789abcdef"[x & 0xf]; + x >>= 4; + } while (x > 0); + break; + default: + do { + i--; + s[i] = "0123456789abcdefghijklmnopqrstuvwxyz"[x % base]; + x /= base; + } while (x > 0); + } + + return (&s[i]); +} + +/* + * Define a custom assert() in order to reduce the chances of deadlock during + * assertion failure. + */ +#ifdef MALLOC_DEBUG +# define assert(e) do { \ + if (!(e)) { \ + char line_buf[UMAX2S_BUFSIZE]; \ + _malloc_message(_getprogname(), ": (malloc) ", \ + __FILE__, ":"); \ + _malloc_message(umax2s(__LINE__, 10, line_buf), \ + ": Failed assertion: ", "\"", #e); \ + _malloc_message("\"\n", "", "", ""); \ + abort(); \ + } \ +} while (0) +#else +#define assert(e) +#endif + +#ifdef MALLOC_STATS +/* + * Print to stderr in such a way as to (hopefully) avoid memory allocation. + */ +static void +malloc_printf(const char *format, ...) +{ + char buf[4096]; + va_list ap; + + va_start(ap, format); + vsnprintf(buf, sizeof(buf), format, ap); + va_end(ap); + _malloc_message(buf, "", "", ""); +} +#endif + +/******************************************************************************/ /* * Begin mutex. We can't use normal pthread mutexes in all places, because * they require malloc()ed memory, which causes bootstrapping issues in some @@ -1255,10 +1461,9 @@ malloc_spin_init(pthread_mutex_t *lock) return (false); } -static inline unsigned +static inline void malloc_spin_lock(pthread_mutex_t *lock) { - unsigned ret = 0; if (__isthreaded) { if (_pthread_mutex_trylock(lock) != 0) { @@ -1267,14 +1472,13 @@ malloc_spin_lock(pthread_mutex_t *lock) unsigned i; volatile unsigned j; - for (i = 1; i <= SPIN_LIMIT_2POW; i++) { + for (i = 1; i <= LG_SPIN_LIMIT; i++) { for (j = 0; j < (1U << i); j++) { - ret++; CPU_SPINWAIT; } if (_pthread_mutex_trylock(lock) == 0) - return (ret); + return; } } @@ -1284,12 +1488,8 @@ malloc_spin_lock(pthread_mutex_t *lock) * inversion. */ _pthread_mutex_lock(lock); - assert((ret << BLOCK_COST_2POW) != 0 || ncpus == 1); - return (ret << BLOCK_COST_2POW); } } - - return (ret); } static inline void @@ -1332,13 +1532,17 @@ malloc_spin_unlock(pthread_mutex_t *lock) #define SUBPAGE_CEILING(s) \ (((s) + SUBPAGE_MASK) & ~SUBPAGE_MASK) -/* Return the smallest PAGE_SIZE multiple that is >= s. */ +/* Return the smallest medium size class that is >= s. */ +#define MEDIUM_CEILING(s) \ + (((s) + mspace_mask) & ~mspace_mask) + +/* Return the smallest pagesize multiple that is >= s. */ #define PAGE_CEILING(s) \ (((s) + PAGE_MASK) & ~PAGE_MASK) #ifdef MALLOC_TINY /* Compute the smallest power of 2 that is >= x. */ -static inline size_t +static size_t pow2_ceil(size_t x) { @@ -1356,112 +1560,6 @@ pow2_ceil(size_t x) } #endif -#ifdef MALLOC_BALANCE -/* - * Use a simple linear congruential pseudo-random number generator: - * - * prn(y) = (a*x + c) % m - * - * where the following constants ensure maximal period: - * - * a == Odd number (relatively prime to 2^n), and (a-1) is a multiple of 4. - * c == Odd number (relatively prime to 2^n). - * m == 2^32 - * - * See Knuth's TAOCP 3rd Ed., Vol. 2, pg. 17 for details on these constraints. - * - * This choice of m has the disadvantage that the quality of the bits is - * proportional to bit position. For example. the lowest bit has a cycle of 2, - * the next has a cycle of 4, etc. For this reason, we prefer to use the upper - * bits. - */ -# define PRN_DEFINE(suffix, var, a, c) \ -static inline void \ -sprn_##suffix(uint32_t seed) \ -{ \ - var = seed; \ -} \ - \ -static inline uint32_t \ -prn_##suffix(uint32_t lg_range) \ -{ \ - uint32_t ret, x; \ - \ - assert(lg_range > 0); \ - assert(lg_range <= 32); \ - \ - x = (var * (a)) + (c); \ - var = x; \ - ret = x >> (32 - lg_range); \ - \ - return (ret); \ -} -# define SPRN(suffix, seed) sprn_##suffix(seed) -# define PRN(suffix, lg_range) prn_##suffix(lg_range) -#endif - -#ifdef MALLOC_BALANCE -/* Define the PRNG used for arena assignment. */ -static __thread uint32_t balance_x; -PRN_DEFINE(balance, balance_x, 1297, 1301) -#endif - -static void -wrtmessage(const char *p1, const char *p2, const char *p3, const char *p4) -{ - - _write(STDERR_FILENO, p1, strlen(p1)); - _write(STDERR_FILENO, p2, strlen(p2)); - _write(STDERR_FILENO, p3, strlen(p3)); - _write(STDERR_FILENO, p4, strlen(p4)); -} - -void (*_malloc_message)(const char *p1, const char *p2, const char *p3, - const char *p4) = wrtmessage; - -#ifdef MALLOC_STATS -/* - * Print to stderr in such a way as to (hopefully) avoid memory allocation. - */ -static void -malloc_printf(const char *format, ...) -{ - char buf[4096]; - va_list ap; - - va_start(ap, format); - vsnprintf(buf, sizeof(buf), format, ap); - va_end(ap); - _malloc_message(buf, "", "", ""); -} -#endif - -/* - * We don't want to depend on vsnprintf() for production builds, since that can - * cause unnecessary bloat for static binaries. umax2s() provides minimal - * integer printing functionality, so that malloc_printf() use can be limited to - * MALLOC_STATS code. - */ -#define UMAX2S_BUFSIZE 21 -static char * -umax2s(uintmax_t x, char *s) -{ - unsigned i; - - /* Make sure UMAX2S_BUFSIZE is large enough. */ - assert(sizeof(uintmax_t) <= 8); - - i = UMAX2S_BUFSIZE - 1; - s[i] = '\0'; - do { - i--; - s[i] = "0123456789"[x % 10]; - x /= 10; - } while (x > 0); - - return (&s[i]); -} - /******************************************************************************/ #ifdef MALLOC_DSS @@ -1587,7 +1685,8 @@ base_calloc(size_t number, size_t size) void *ret; ret = base_alloc(number * size); - memset(ret, 0, number * size); + if (ret != NULL) + memset(ret, 0, number * size); return (ret); } @@ -1620,93 +1719,6 @@ base_node_dealloc(extent_node_t *node) malloc_mutex_unlock(&base_mtx); } -/******************************************************************************/ - -#ifdef MALLOC_STATS -static void -stats_print(arena_t *arena) -{ - unsigned i, gap_start; - - malloc_printf("dirty: %zu page%s dirty, %llu sweep%s," - " %llu madvise%s, %llu page%s purged\n", - arena->ndirty, arena->ndirty == 1 ? "" : "s", - arena->stats.npurge, arena->stats.npurge == 1 ? "" : "s", - arena->stats.nmadvise, arena->stats.nmadvise == 1 ? "" : "s", - arena->stats.purged, arena->stats.purged == 1 ? "" : "s"); - - malloc_printf(" allocated nmalloc ndalloc\n"); - malloc_printf("small: %12zu %12llu %12llu\n", - arena->stats.allocated_small, arena->stats.nmalloc_small, - arena->stats.ndalloc_small); - malloc_printf("large: %12zu %12llu %12llu\n", - arena->stats.allocated_large, arena->stats.nmalloc_large, - arena->stats.ndalloc_large); - malloc_printf("total: %12zu %12llu %12llu\n", - arena->stats.allocated_small + arena->stats.allocated_large, - arena->stats.nmalloc_small + arena->stats.nmalloc_large, - arena->stats.ndalloc_small + arena->stats.ndalloc_large); - malloc_printf("mapped: %12zu\n", arena->stats.mapped); - -#ifdef MALLOC_MAG - if (__isthreaded && opt_mag) { - malloc_printf("bins: bin size regs pgs mags " - "newruns reruns maxruns curruns\n"); - } else { -#endif - malloc_printf("bins: bin size regs pgs requests " - "newruns reruns maxruns curruns\n"); -#ifdef MALLOC_MAG - } -#endif - for (i = 0, gap_start = UINT_MAX; i < nbins; i++) { - if (arena->bins[i].stats.nruns == 0) { - if (gap_start == UINT_MAX) - gap_start = i; - } else { - if (gap_start != UINT_MAX) { - if (i > gap_start + 1) { - /* Gap of more than one size class. */ - malloc_printf("[%u..%u]\n", - gap_start, i - 1); - } else { - /* Gap of one size class. */ - malloc_printf("[%u]\n", gap_start); - } - gap_start = UINT_MAX; - } - malloc_printf( - "%13u %1s %4u %4u %3u %9llu %9llu" - " %9llu %7lu %7lu\n", - i, - i < ntbins ? "T" : i < ntbins + nqbins ? "Q" : - i < ntbins + nqbins + ncbins ? "C" : "S", - arena->bins[i].reg_size, - arena->bins[i].nregs, - arena->bins[i].run_size >> PAGE_SHIFT, -#ifdef MALLOC_MAG - (__isthreaded && opt_mag) ? - arena->bins[i].stats.nmags : -#endif - arena->bins[i].stats.nrequests, - arena->bins[i].stats.nruns, - arena->bins[i].stats.reruns, - arena->bins[i].stats.highruns, - arena->bins[i].stats.curruns); - } - } - if (gap_start != UINT_MAX) { - if (i > gap_start + 1) { - /* Gap of more than one size class. */ - malloc_printf("[%u..%u]\n", gap_start, i - 1); - } else { - /* Gap of one size class. */ - malloc_printf("[%u]\n", gap_start); - } - } -} -#endif - /* * End Utility functions/macros. */ @@ -1813,8 +1825,13 @@ pages_unmap(void *addr, size_t size) #ifdef MALLOC_DSS static void * -chunk_alloc_dss(size_t size) +chunk_alloc_dss(size_t size, bool *zero) { + void *ret; + + ret = chunk_recycle_dss(size, zero); + if (ret != NULL) + return (ret); /* * sbrk() uses a signed increment argument, so take care not to @@ -1833,8 +1850,6 @@ chunk_alloc_dss(size_t size) * malloc. */ do { - void *ret; - /* Get the current end of the DSS. */ dss_max = sbrk(0); @@ -1856,6 +1871,7 @@ chunk_alloc_dss(size_t size) /* Success. */ dss_max = (void *)((intptr_t)dss_prev + incr); malloc_mutex_unlock(&dss_mtx); + *zero = true; return (ret); } } while (dss_prev != (void *)-1); @@ -1866,7 +1882,7 @@ chunk_alloc_dss(size_t size) } static void * -chunk_recycle_dss(size_t size, bool zero) +chunk_recycle_dss(size_t size, bool *zero) { extent_node_t *node, key; @@ -1895,7 +1911,7 @@ chunk_recycle_dss(size_t size, bool zero) } malloc_mutex_unlock(&dss_mtx); - if (zero) + if (*zero) memset(ret, 0, size); return (ret); } @@ -1906,82 +1922,124 @@ chunk_recycle_dss(size_t size, bool zero) #endif static void * -chunk_alloc_mmap(size_t size) +chunk_alloc_mmap_slow(size_t size, bool unaligned) { void *ret; size_t offset; - /* - * Ideally, there would be a way to specify alignment to mmap() (like - * NetBSD has), but in the absence of such a feature, we have to work - * hard to efficiently create aligned mappings. The reliable, but - * expensive method is to create a mapping that is over-sized, then - * trim the excess. However, that always results in at least one call - * to pages_unmap(). - * - * A more optimistic approach is to try mapping precisely the right - * amount, then try to append another mapping if alignment is off. In - * practice, this works out well as long as the application is not - * interleaving mappings via direct mmap() calls. If we do run into a - * situation where there is an interleaved mapping and we are unable to - * extend an unaligned mapping, our best option is to momentarily - * revert to the reliable-but-expensive method. This will tend to - * leave a gap in the memory map that is too small to cause later - * problems for the optimistic method. - */ + /* Beware size_t wrap-around. */ + if (size + chunksize <= size) + return (NULL); - ret = pages_map(NULL, size); + ret = pages_map(NULL, size + chunksize); if (ret == NULL) return (NULL); + /* Clean up unneeded leading/trailing space. */ offset = CHUNK_ADDR2OFFSET(ret); if (offset != 0) { - /* Try to extend chunk boundary. */ - if (pages_map((void *)((uintptr_t)ret + size), - chunksize - offset) == NULL) { - /* - * Extension failed. Clean up, then revert to the - * reliable-but-expensive method. - */ - pages_unmap(ret, size); + /* Note that mmap() returned an unaligned mapping. */ + unaligned = true; - /* Beware size_t wrap-around. */ - if (size + chunksize <= size) - return NULL; + /* Leading space. */ + pages_unmap(ret, chunksize - offset); - ret = pages_map(NULL, size + chunksize); - if (ret == NULL) - return (NULL); + ret = (void *)((uintptr_t)ret + + (chunksize - offset)); - /* Clean up unneeded leading/trailing space. */ - offset = CHUNK_ADDR2OFFSET(ret); - if (offset != 0) { - /* Leading space. */ - pages_unmap(ret, chunksize - offset); + /* Trailing space. */ + pages_unmap((void *)((uintptr_t)ret + size), + offset); + } else { + /* Trailing space only. */ + pages_unmap((void *)((uintptr_t)ret + size), + chunksize); + } + + /* + * If mmap() returned an aligned mapping, reset mmap_unaligned so that + * the next chunk_alloc_mmap() execution tries the fast allocation + * method. + */ + if (unaligned == false) + mmap_unaligned = false; + + return (ret); +} + +static void * +chunk_alloc_mmap(size_t size) +{ + void *ret; + + /* + * Ideally, there would be a way to specify alignment to mmap() (like + * NetBSD has), but in the absence of such a feature, we have to work + * hard to efficiently create aligned mappings. The reliable, but + * slow method is to create a mapping that is over-sized, then trim the + * excess. However, that always results in at least one call to + * pages_unmap(). + * + * A more optimistic approach is to try mapping precisely the right + * amount, then try to append another mapping if alignment is off. In + * practice, this works out well as long as the application is not + * interleaving mappings via direct mmap() calls. If we do run into a + * situation where there is an interleaved mapping and we are unable to + * extend an unaligned mapping, our best option is to switch to the + * slow method until mmap() returns another aligned mapping. This will + * tend to leave a gap in the memory map that is too small to cause + * later problems for the optimistic method. + * + * Another possible confounding factor is address space layout + * randomization (ASLR), which causes mmap(2) to disregard the + * requested address. mmap_unaligned tracks whether the previous + * chunk_alloc_mmap() execution received any unaligned or relocated + * mappings, and if so, the current execution will immediately fall + * back to the slow method. However, we keep track of whether the fast + * method would have succeeded, and if so, we make a note to try the + * fast method next time. + */ - ret = (void *)((uintptr_t)ret + - (chunksize - offset)); + if (mmap_unaligned == false) { + size_t offset; + + ret = pages_map(NULL, size); + if (ret == NULL) + return (NULL); - /* Trailing space. */ - pages_unmap((void *)((uintptr_t)ret + size), - offset); + offset = CHUNK_ADDR2OFFSET(ret); + if (offset != 0) { + mmap_unaligned = true; + /* Try to extend chunk boundary. */ + if (pages_map((void *)((uintptr_t)ret + size), + chunksize - offset) == NULL) { + /* + * Extension failed. Clean up, then revert to + * the reliable-but-expensive method. + */ + pages_unmap(ret, size); + ret = chunk_alloc_mmap_slow(size, true); } else { - /* Trailing space only. */ - pages_unmap((void *)((uintptr_t)ret + size), - chunksize); + /* Clean up unneeded leading space. */ + pages_unmap(ret, chunksize - offset); + ret = (void *)((uintptr_t)ret + (chunksize - + offset)); } - } else { - /* Clean up unneeded leading space. */ - pages_unmap(ret, chunksize - offset); - ret = (void *)((uintptr_t)ret + (chunksize - offset)); } - } + } else + ret = chunk_alloc_mmap_slow(size, false); return (ret); } +/* + * If the caller specifies (*zero == false), it is still possible to receive + * zeroed memory, in which case *zero is toggled to true. arena_chunk_alloc() + * takes advantage of this to avoid demanding zeroed chunks, but taking + * advantage of them if they are returned. + */ static void * -chunk_alloc(size_t size, bool zero) +chunk_alloc(size_t size, bool *zero) { void *ret; @@ -1993,18 +2051,15 @@ chunk_alloc(size_t size, bool zero) #endif { ret = chunk_alloc_mmap(size); - if (ret != NULL) + if (ret != NULL) { + *zero = true; goto RETURN; + } } #ifdef MALLOC_DSS if (opt_dss) { - ret = chunk_recycle_dss(size, zero); - if (ret != NULL) { - goto RETURN; - } - - ret = chunk_alloc_dss(size); + ret = chunk_alloc_dss(size, zero); if (ret != NULL) goto RETURN; } @@ -2015,11 +2070,13 @@ chunk_alloc(size_t size, bool zero) RETURN: #ifdef MALLOC_STATS if (ret != NULL) { + malloc_mutex_lock(&chunks_mtx); stats_chunks.nchunks += (size / chunksize); stats_chunks.curchunks += (size / chunksize); + if (stats_chunks.curchunks > stats_chunks.highchunks) + stats_chunks.highchunks = stats_chunks.curchunks; + malloc_mutex_unlock(&chunks_mtx); } - if (stats_chunks.curchunks > stats_chunks.highchunks) - stats_chunks.highchunks = stats_chunks.curchunks; #endif assert(CHUNK_ADDR2BASE(ret) == ret); @@ -2088,6 +2145,7 @@ chunk_dealloc_dss_record(void *chunk, size_t size) static bool chunk_dealloc_dss(void *chunk, size_t size) { + bool ret; malloc_mutex_lock(&dss_mtx); if ((uintptr_t)chunk >= (uintptr_t)dss_base @@ -2121,17 +2179,17 @@ chunk_dealloc_dss(void *chunk, size_t size) extent_tree_ad_remove(&dss_chunks_ad, node); base_node_dealloc(node); } - malloc_mutex_unlock(&dss_mtx); - } else { - malloc_mutex_unlock(&dss_mtx); + } else madvise(chunk, size, MADV_FREE); - } - return (false); + ret = false; + goto RETURN; } - malloc_mutex_unlock(&dss_mtx); - return (true); + ret = true; +RETURN: + malloc_mutex_unlock(&dss_mtx); + return (ret); } #endif @@ -2152,7 +2210,9 @@ chunk_dealloc(void *chunk, size_t size) assert((size & chunksize_mask) == 0); #ifdef MALLOC_STATS + malloc_mutex_lock(&chunks_mtx); stats_chunks.curchunks -= (size / chunksize); + malloc_mutex_unlock(&chunks_mtx); #endif #ifdef MALLOC_DSS @@ -2259,29 +2319,12 @@ choose_arena_hard(void) assert(__isthreaded); -#ifdef MALLOC_BALANCE - /* Seed the PRNG used for arena load balancing. */ - SPRN(balance, (uint32_t)(uintptr_t)(_pthread_self())); -#endif - if (narenas > 1) { -#ifdef MALLOC_BALANCE - unsigned ind; - - ind = PRN(balance, narenas_2pow); - if ((ret = arenas[ind]) == NULL) { - malloc_spin_lock(&arenas_lock); - if ((ret = arenas[ind]) == NULL) - ret = arenas_extend(ind); - malloc_spin_unlock(&arenas_lock); - } -#else malloc_spin_lock(&arenas_lock); if ((ret = arenas[next_arena]) == NULL) ret = arenas_extend(next_arena); next_arena = (next_arena + 1) % narenas; malloc_spin_unlock(&arenas_lock); -#endif } else ret = arenas[0]; @@ -2334,7 +2377,7 @@ arena_avail_comp(arena_chunk_map_t *a, arena_chunk_map_t *b) if (ret == 0) { uintptr_t a_mapelm, b_mapelm; - if ((a->bits & CHUNK_MAP_KEY) == 0) + if ((a->bits & CHUNK_MAP_KEY) != CHUNK_MAP_KEY) a_mapelm = (uintptr_t)a; else { /* @@ -2355,6 +2398,105 @@ arena_avail_comp(arena_chunk_map_t *a, arena_chunk_map_t *b) rb_wrap(__unused static, arena_avail_tree_, arena_avail_tree_t, arena_chunk_map_t, link, arena_avail_comp) +static inline void +arena_run_rc_incr(arena_run_t *run, arena_bin_t *bin, const void *ptr) +{ + arena_chunk_t *chunk; + arena_t *arena; + size_t pagebeg, pageend, i; + + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); + arena = chunk->arena; + pagebeg = ((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT; + pageend = ((uintptr_t)ptr + (uintptr_t)(bin->reg_size - 1) - + (uintptr_t)chunk) >> PAGE_SHIFT; + + for (i = pagebeg; i <= pageend; i++) { + size_t mapbits = chunk->map[i].bits; + + if (mapbits & CHUNK_MAP_DIRTY) { + assert((mapbits & CHUNK_MAP_RC_MASK) == 0); + chunk->ndirty--; + arena->ndirty--; + mapbits ^= CHUNK_MAP_DIRTY; + } + assert((mapbits & CHUNK_MAP_RC_MASK) != CHUNK_MAP_RC_MASK); + mapbits += CHUNK_MAP_RC_ONE; + chunk->map[i].bits = mapbits; + } +} + +static inline void +arena_run_rc_decr(arena_run_t *run, arena_bin_t *bin, const void *ptr) +{ + arena_chunk_t *chunk; + arena_t *arena; + size_t pagebeg, pageend, mapbits, i; + bool dirtier = false; + + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); + arena = chunk->arena; + pagebeg = ((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT; + pageend = ((uintptr_t)ptr + (uintptr_t)(bin->reg_size - 1) - + (uintptr_t)chunk) >> PAGE_SHIFT; + + /* First page. */ + mapbits = chunk->map[pagebeg].bits; + mapbits -= CHUNK_MAP_RC_ONE; + if ((mapbits & CHUNK_MAP_RC_MASK) == 0) { + dirtier = true; + assert((mapbits & CHUNK_MAP_DIRTY) == 0); + mapbits |= CHUNK_MAP_DIRTY; + chunk->ndirty++; + arena->ndirty++; + } + chunk->map[pagebeg].bits = mapbits; + + if (pageend - pagebeg >= 1) { + /* + * Interior pages are completely consumed by the object being + * deallocated, which means that the pages can be + * unconditionally marked dirty. + */ + for (i = pagebeg + 1; i < pageend; i++) { + mapbits = chunk->map[i].bits; + mapbits -= CHUNK_MAP_RC_ONE; + assert((mapbits & CHUNK_MAP_RC_MASK) == 0); + dirtier = true; + assert((mapbits & CHUNK_MAP_DIRTY) == 0); + mapbits |= CHUNK_MAP_DIRTY; + chunk->ndirty++; + arena->ndirty++; + chunk->map[i].bits = mapbits; + } + + /* Last page. */ + mapbits = chunk->map[pageend].bits; + mapbits -= CHUNK_MAP_RC_ONE; + if ((mapbits & CHUNK_MAP_RC_MASK) == 0) { + dirtier = true; + assert((mapbits & CHUNK_MAP_DIRTY) == 0); + mapbits |= CHUNK_MAP_DIRTY; + chunk->ndirty++; + arena->ndirty++; + } + chunk->map[pageend].bits = mapbits; + } + + if (dirtier) { + if (chunk->dirtied == false) { + arena_chunk_tree_dirty_insert(&arena->chunks_dirty, + chunk); + chunk->dirtied = true; + } + + /* Enforce opt_lg_dirty_mult. */ + if (opt_lg_dirty_mult >= 0 && (arena->nactive >> + opt_lg_dirty_mult) < arena->ndirty) + arena_purge(arena); + } +} + static inline void * arena_run_reg_alloc(arena_run_t *run, arena_bin_t *bin) { @@ -2375,7 +2517,7 @@ arena_run_reg_alloc(arena_run_t *run, arena_bin_t *bin) /* Usable allocation found. */ bit = ffs((int)mask) - 1; - regind = ((i << (SIZEOF_INT_2POW + 3)) + bit); + regind = ((i << (LG_SIZEOF_INT + 3)) + bit); assert(regind < bin->nregs); ret = (void *)(((uintptr_t)run) + bin->reg0_offset + (bin->reg_size * regind)); @@ -2384,6 +2526,8 @@ arena_run_reg_alloc(arena_run_t *run, arena_bin_t *bin) mask ^= (1U << bit); run->regs_mask[i] = mask; + arena_run_rc_incr(run, bin, ret); + return (ret); } @@ -2393,7 +2537,7 @@ arena_run_reg_alloc(arena_run_t *run, arena_bin_t *bin) /* Usable allocation found. */ bit = ffs((int)mask) - 1; - regind = ((i << (SIZEOF_INT_2POW + 3)) + bit); + regind = ((i << (LG_SIZEOF_INT + 3)) + bit); assert(regind < bin->nregs); ret = (void *)(((uintptr_t)run) + bin->reg0_offset + (bin->reg_size * regind)); @@ -2408,6 +2552,8 @@ arena_run_reg_alloc(arena_run_t *run, arena_bin_t *bin) */ run->regs_minelm = i; /* Low payoff: + (mask == 0); */ + arena_run_rc_incr(run, bin, ret); + return (ret); } } @@ -2475,12 +2621,14 @@ arena_run_reg_dalloc(arena_run_t *run, arena_bin_t *bin, void *ptr, size_t size) assert(diff == regind * size); assert(regind < bin->nregs); - elm = regind >> (SIZEOF_INT_2POW + 3); + elm = regind >> (LG_SIZEOF_INT + 3); if (elm < run->regs_minelm) run->regs_minelm = elm; - bit = regind - (elm << (SIZEOF_INT_2POW + 3)); + bit = regind - (elm << (LG_SIZEOF_INT + 3)); assert((run->regs_mask[elm] & (1U << bit)) == 0); run->regs_mask[elm] |= (1U << bit); + + arena_run_rc_decr(run, bin, ptr); } static void @@ -2502,15 +2650,16 @@ arena_run_split(arena_t *arena, arena_run_t *run, size_t size, bool large, rem_pages = total_pages - need_pages; arena_avail_tree_remove(&arena->runs_avail, &chunk->map[run_ind]); + arena->nactive += need_pages; /* Keep track of trailing unused pages for later use. */ if (rem_pages > 0) { chunk->map[run_ind+need_pages].bits = (rem_pages << PAGE_SHIFT) | (chunk->map[run_ind+need_pages].bits & - PAGE_MASK); + CHUNK_MAP_FLAGS_MASK); chunk->map[run_ind+total_pages-1].bits = (rem_pages << PAGE_SHIFT) | (chunk->map[run_ind+total_pages-1].bits & - PAGE_MASK); + CHUNK_MAP_FLAGS_MASK); arena_avail_tree_insert(&arena->runs_avail, &chunk->map[run_ind+need_pages]); } @@ -2538,22 +2687,26 @@ arena_run_split(arena_t *arena, arena_run_t *run, size_t size, bool large, chunk->map[run_ind + i].bits = CHUNK_MAP_LARGE | CHUNK_MAP_ALLOCATED; } else { - chunk->map[run_ind + i].bits = (size_t)run + chunk->map[run_ind + i].bits = (i << CHUNK_MAP_PG_SHIFT) | CHUNK_MAP_ALLOCATED; } } - /* - * Set the run size only in the first element for large runs. This is - * primarily a debugging aid, since the lack of size info for trailing - * pages only matters if the application tries to operate on an - * interior pointer. - */ - if (large) + if (large) { + /* + * Set the run size only in the first element for large runs. + * This is primarily a debugging aid, since the lack of size + * info for trailing pages only matters if the application + * tries to operate on an interior pointer. + */ chunk->map[run_ind].bits |= size; - - if (chunk->ndirty == 0 && old_ndirty > 0) - arena_chunk_tree_dirty_remove(&arena->chunks_dirty, chunk); + } else { + /* + * Initialize the first page's refcount to 1, so that the run + * header is protected from dirty page purging. + */ + chunk->map[run_ind].bits += CHUNK_MAP_RC_ONE; + } } static arena_chunk_t * @@ -2566,7 +2719,11 @@ arena_chunk_alloc(arena_t *arena) chunk = arena->spare; arena->spare = NULL; } else { - chunk = (arena_chunk_t *)chunk_alloc(chunksize, true); + bool zero; + size_t zeroed; + + zero = false; + chunk = (arena_chunk_t *)chunk_alloc(chunksize, &zero); if (chunk == NULL) return (NULL); #ifdef MALLOC_STATS @@ -2574,6 +2731,7 @@ arena_chunk_alloc(arena_t *arena) #endif chunk->arena = arena; + chunk->dirtied = false; /* * Claim that no pages are in use, since the header is merely @@ -2583,15 +2741,16 @@ arena_chunk_alloc(arena_t *arena) /* * Initialize the map to contain one maximal free untouched run. + * Mark the pages as zeroed iff chunk_alloc() returned a zeroed + * chunk. */ + zeroed = zero ? CHUNK_MAP_ZEROED : 0; for (i = 0; i < arena_chunk_header_npages; i++) chunk->map[i].bits = 0; - chunk->map[i].bits = arena_maxclass | CHUNK_MAP_ZEROED; - for (i++; i < chunk_npages-1; i++) { - chunk->map[i].bits = CHUNK_MAP_ZEROED; - } - chunk->map[chunk_npages-1].bits = arena_maxclass | - CHUNK_MAP_ZEROED; + chunk->map[i].bits = arena_maxclass | zeroed; + for (i++; i < chunk_npages-1; i++) + chunk->map[i].bits = zeroed; + chunk->map[chunk_npages-1].bits = arena_maxclass | zeroed; } /* Insert the run into the runs_avail tree. */ @@ -2606,7 +2765,7 @@ arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk) { if (arena->spare != NULL) { - if (arena->spare->ndirty > 0) { + if (arena->spare->dirtied) { arena_chunk_tree_dirty_remove( &chunk->arena->chunks_dirty, arena->spare); arena->ndirty -= arena->spare->ndirty; @@ -2676,11 +2835,12 @@ arena_purge(arena_t *arena) rb_foreach_begin(arena_chunk_t, link_dirty, &arena->chunks_dirty, chunk) { + assert(chunk->dirtied); ndirty += chunk->ndirty; } rb_foreach_end(arena_chunk_t, link_dirty, &arena->chunks_dirty, chunk) assert(ndirty == arena->ndirty); #endif - assert(arena->ndirty > opt_dirty_max); + assert((arena->nactive >> opt_lg_dirty_mult) < arena->ndirty); #ifdef MALLOC_STATS arena->stats.npurge++; @@ -2692,13 +2852,13 @@ arena_purge(arena_t *arena) * number of system calls, even if a chunk has only been partially * purged. */ - while (arena->ndirty > (opt_dirty_max >> 1)) { + + while ((arena->nactive >> (opt_lg_dirty_mult + 1)) < arena->ndirty) { chunk = arena_chunk_tree_dirty_last(&arena->chunks_dirty); assert(chunk != NULL); for (i = chunk_npages - 1; chunk->ndirty > 0; i--) { assert(i >= arena_chunk_header_npages); - if (chunk->map[i].bits & CHUNK_MAP_DIRTY) { chunk->map[i].bits ^= CHUNK_MAP_DIRTY; /* Find adjacent dirty run(s). */ @@ -2718,7 +2878,8 @@ arena_purge(arena_t *arena) arena->stats.nmadvise++; arena->stats.purged += npages; #endif - if (arena->ndirty <= (opt_dirty_max >> 1)) + if ((arena->nactive >> (opt_lg_dirty_mult + 1)) + >= arena->ndirty) break; } } @@ -2726,6 +2887,7 @@ arena_purge(arena_t *arena) if (chunk->ndirty == 0) { arena_chunk_tree_dirty_remove(&arena->chunks_dirty, chunk); + chunk->dirtied = false; } } } @@ -2746,23 +2908,26 @@ arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty) else size = run->bin->run_size; run_pages = (size >> PAGE_SHIFT); + arena->nactive -= run_pages; /* Mark pages as unallocated in the chunk map. */ if (dirty) { size_t i; for (i = 0; i < run_pages; i++) { + /* + * When (dirty == true), *all* pages within the run + * need to have their dirty bits set, because only + * small runs can create a mixture of clean/dirty + * pages, but such runs are passed to this function + * with (dirty == false). + */ assert((chunk->map[run_ind + i].bits & CHUNK_MAP_DIRTY) == 0); + chunk->ndirty++; + arena->ndirty++; chunk->map[run_ind + i].bits = CHUNK_MAP_DIRTY; } - - if (chunk->ndirty == 0) { - arena_chunk_tree_dirty_insert(&arena->chunks_dirty, - chunk); - } - chunk->ndirty += run_pages; - arena->ndirty += run_pages; } else { size_t i; @@ -2772,9 +2937,9 @@ arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty) } } chunk->map[run_ind].bits = size | (chunk->map[run_ind].bits & - PAGE_MASK); + CHUNK_MAP_FLAGS_MASK); chunk->map[run_ind+run_pages-1].bits = size | - (chunk->map[run_ind+run_pages-1].bits & PAGE_MASK); + (chunk->map[run_ind+run_pages-1].bits & CHUNK_MAP_FLAGS_MASK); /* Try to coalesce forward. */ if (run_ind + run_pages < chunk_npages && @@ -2795,9 +2960,10 @@ arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty) assert((chunk->map[run_ind+run_pages-1].bits & ~PAGE_MASK) == nrun_size); chunk->map[run_ind].bits = size | (chunk->map[run_ind].bits & - PAGE_MASK); + CHUNK_MAP_FLAGS_MASK); chunk->map[run_ind+run_pages-1].bits = size | - (chunk->map[run_ind+run_pages-1].bits & PAGE_MASK); + (chunk->map[run_ind+run_pages-1].bits & + CHUNK_MAP_FLAGS_MASK); } /* Try to coalesce backward. */ @@ -2817,25 +2983,45 @@ arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty) size += prun_size; run_pages = size >> PAGE_SHIFT; - assert((chunk->map[run_ind].bits & ~PAGE_MASK) == - prun_size); + assert((chunk->map[run_ind].bits & ~PAGE_MASK) == prun_size); chunk->map[run_ind].bits = size | (chunk->map[run_ind].bits & - PAGE_MASK); + CHUNK_MAP_FLAGS_MASK); chunk->map[run_ind+run_pages-1].bits = size | - (chunk->map[run_ind+run_pages-1].bits & PAGE_MASK); + (chunk->map[run_ind+run_pages-1].bits & + CHUNK_MAP_FLAGS_MASK); } /* Insert into runs_avail, now that coalescing is complete. */ arena_avail_tree_insert(&arena->runs_avail, &chunk->map[run_ind]); - /* Deallocate chunk if it is now completely unused. */ + /* + * Deallocate chunk if it is now completely unused. The bit + * manipulation checks whether the first run is unallocated and extends + * to the end of the chunk. + */ if ((chunk->map[arena_chunk_header_npages].bits & (~PAGE_MASK | CHUNK_MAP_ALLOCATED)) == arena_maxclass) arena_chunk_dealloc(arena, chunk); - /* Enforce opt_dirty_max. */ - if (arena->ndirty > opt_dirty_max) - arena_purge(arena); + /* + * It is okay to do dirty page processing even if the chunk was + * deallocated above, since in that case it is the spare. Waiting + * until after possible chunk deallocation to do dirty processing + * allows for an old spare to be fully deallocated, thus decreasing the + * chances of spuriously crossing the dirty page purging threshold. + */ + if (dirty) { + if (chunk->dirtied == false) { + arena_chunk_tree_dirty_insert(&arena->chunks_dirty, + chunk); + chunk->dirtied = true; + } + + /* Enforce opt_lg_dirty_mult. */ + if (opt_lg_dirty_mult >= 0 && (arena->nactive >> + opt_lg_dirty_mult) < arena->ndirty) + arena_purge(arena); + } } static void @@ -2851,8 +3037,10 @@ arena_run_trim_head(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run, * Update the chunk map so that arena_run_dalloc() can treat the * leading run as separately allocated. */ + assert((chunk->map[pageind].bits & CHUNK_MAP_DIRTY) == 0); chunk->map[pageind].bits = (oldsize - newsize) | CHUNK_MAP_LARGE | CHUNK_MAP_ALLOCATED; + assert((chunk->map[pageind+head_npages].bits & CHUNK_MAP_DIRTY) == 0); chunk->map[pageind+head_npages].bits = newsize | CHUNK_MAP_LARGE | CHUNK_MAP_ALLOCATED; @@ -2872,8 +3060,10 @@ arena_run_trim_tail(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run, * Update the chunk map so that arena_run_dalloc() can treat the * trailing run as separately allocated. */ + assert((chunk->map[pageind].bits & CHUNK_MAP_DIRTY) == 0); chunk->map[pageind].bits = newsize | CHUNK_MAP_LARGE | CHUNK_MAP_ALLOCATED; + assert((chunk->map[pageind+npages].bits & CHUNK_MAP_DIRTY) == 0); chunk->map[pageind+npages].bits = (oldsize - newsize) | CHUNK_MAP_LARGE | CHUNK_MAP_ALLOCATED; @@ -2891,9 +3081,18 @@ arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin) /* Look for a usable run. */ mapelm = arena_run_tree_first(&bin->runs); if (mapelm != NULL) { + arena_chunk_t *chunk; + size_t pageind; + /* run is guaranteed to have available space. */ arena_run_tree_remove(&bin->runs, mapelm); - run = (arena_run_t *)(mapelm->bits & ~PAGE_MASK); + + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(mapelm); + pageind = (((uintptr_t)mapelm - (uintptr_t)chunk->map) / + sizeof(arena_chunk_map_t)); + run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind - + ((mapelm->bits & CHUNK_MAP_PG_MASK) >> CHUNK_MAP_PG_SHIFT)) + << PAGE_SHIFT)); #ifdef MALLOC_STATS bin->stats.reruns++; #endif @@ -2911,12 +3110,12 @@ arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin) for (i = 0; i < bin->regs_mask_nelms - 1; i++) run->regs_mask[i] = UINT_MAX; - remainder = bin->nregs & ((1U << (SIZEOF_INT_2POW + 3)) - 1); + remainder = bin->nregs & ((1U << (LG_SIZEOF_INT + 3)) - 1); if (remainder == 0) run->regs_mask[i] = UINT_MAX; else { /* The last element has spare bits that need to be unset. */ - run->regs_mask[i] = (UINT_MAX >> ((1U << (SIZEOF_INT_2POW + 3)) + run->regs_mask[i] = (UINT_MAX >> ((1U << (LG_SIZEOF_INT + 3)) - remainder)); } @@ -2973,6 +3172,7 @@ arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin) * *) bin->run_size <= arena_maxclass * *) bin->run_size <= RUN_MAX_SMALL * *) run header overhead <= RUN_MAX_OVRHD (or header overhead relaxed). + * *) run header size < PAGE_SIZE * * bin->nregs, bin->regs_mask_nelms, and bin->reg0_offset are * also calculated here, since these settings are all interdependent. @@ -3003,8 +3203,8 @@ arena_bin_run_size_calc(arena_bin_t *bin, size_t min_run_size) + 1; /* Counter-act try_nregs-- in loop. */ do { try_nregs--; - try_mask_nelms = (try_nregs >> (SIZEOF_INT_2POW + 3)) + - ((try_nregs & ((1U << (SIZEOF_INT_2POW + 3)) - 1)) ? 1 : 0); + try_mask_nelms = (try_nregs >> (LG_SIZEOF_INT + 3)) + + ((try_nregs & ((1U << (LG_SIZEOF_INT + 3)) - 1)) ? 1 : 0); try_reg0_offset = try_run_size - (try_nregs * bin->reg_size); } while (sizeof(arena_run_t) + (sizeof(unsigned) * (try_mask_nelms - 1)) > try_reg0_offset); @@ -3025,8 +3225,8 @@ arena_bin_run_size_calc(arena_bin_t *bin, size_t min_run_size) bin->reg_size) + 1; /* Counter-act try_nregs-- in loop. */ do { try_nregs--; - try_mask_nelms = (try_nregs >> (SIZEOF_INT_2POW + 3)) + - ((try_nregs & ((1U << (SIZEOF_INT_2POW + 3)) - 1)) ? + try_mask_nelms = (try_nregs >> (LG_SIZEOF_INT + 3)) + + ((try_nregs & ((1U << (LG_SIZEOF_INT + 3)) - 1)) ? 1 : 0); try_reg0_offset = try_run_size - (try_nregs * bin->reg_size); @@ -3034,11 +3234,13 @@ arena_bin_run_size_calc(arena_bin_t *bin, size_t min_run_size) (try_mask_nelms - 1)) > try_reg0_offset); } while (try_run_size <= arena_maxclass && try_run_size <= RUN_MAX_SMALL && RUN_MAX_OVRHD * (bin->reg_size << 3) > RUN_MAX_OVRHD_RELAX - && (try_reg0_offset << RUN_BFP) > RUN_MAX_OVRHD * try_run_size); + && (try_reg0_offset << RUN_BFP) > RUN_MAX_OVRHD * try_run_size + && (sizeof(arena_run_t) + (sizeof(unsigned) * (try_mask_nelms - 1))) + < PAGE_SIZE); assert(sizeof(arena_run_t) + (sizeof(unsigned) * (good_mask_nelms - 1)) <= good_reg0_offset); - assert((good_mask_nelms << (SIZEOF_INT_2POW + 3)) >= good_nregs); + assert((good_mask_nelms << (LG_SIZEOF_INT + 3)) >= good_nregs); /* Copy final settings. */ bin->run_size = good_run_size; @@ -3049,141 +3251,137 @@ arena_bin_run_size_calc(arena_bin_t *bin, size_t min_run_size) return (good_run_size); } -#ifdef MALLOC_BALANCE +#ifdef MALLOC_TCACHE static inline void -arena_lock_balance(arena_t *arena) +tcache_event(tcache_t *tcache) { - unsigned contention; - contention = malloc_spin_lock(&arena->lock); - if (narenas > 1) { - /* - * Calculate the exponentially averaged contention for this - * arena. Due to integer math always rounding down, this value - * decays somewhat faster than normal. - */ - arena->contention = (((uint64_t)arena->contention - * (uint64_t)((1U << BALANCE_ALPHA_INV_2POW)-1)) - + (uint64_t)contention) >> BALANCE_ALPHA_INV_2POW; - if (arena->contention >= opt_balance_threshold) - arena_lock_balance_hard(arena); - } -} + if (tcache_gc_incr == 0) + return; -static void -arena_lock_balance_hard(arena_t *arena) -{ - uint32_t ind; + tcache->ev_cnt++; + assert(tcache->ev_cnt <= tcache_gc_incr); + if (tcache->ev_cnt >= tcache_gc_incr) { + size_t binind = tcache->next_gc_bin; + tcache_bin_t *tbin = tcache->tbins[binind]; - arena->contention = 0; -#ifdef MALLOC_STATS - arena->stats.nbalance++; -#endif - ind = PRN(balance, narenas_2pow); - if (arenas[ind] != NULL) - arenas_map = arenas[ind]; - else { - malloc_spin_lock(&arenas_lock); - if (arenas[ind] != NULL) - arenas_map = arenas[ind]; - else - arenas_map = arenas_extend(ind); - malloc_spin_unlock(&arenas_lock); + if (tbin != NULL) { + if (tbin->high_water == 0) { + /* + * This bin went completely unused for an + * entire GC cycle, so throw away the tbin. + */ + assert(tbin->ncached == 0); + tcache_bin_destroy(tcache, tbin, binind); + tcache->tbins[binind] = NULL; + } else { + if (tbin->low_water > 0) { + /* + * Flush (ceiling) half of the objects + * below the low water mark. + */ + tcache_bin_flush(tbin, binind, + tbin->ncached - (tbin->low_water >> + 1) - (tbin->low_water & 1)); + } + tbin->low_water = tbin->ncached; + tbin->high_water = tbin->ncached; + } + } + + tcache->next_gc_bin++; + if (tcache->next_gc_bin == nbins) + tcache->next_gc_bin = 0; + tcache->ev_cnt = 0; } } -#endif -#ifdef MALLOC_MAG static inline void * -mag_alloc(mag_t *mag) +tcache_bin_alloc(tcache_bin_t *tbin) { - if (mag->nrounds == 0) + if (tbin->ncached == 0) return (NULL); - mag->nrounds--; - - return (mag->rounds[mag->nrounds]); + tbin->ncached--; + if (tbin->ncached < tbin->low_water) + tbin->low_water = tbin->ncached; + return (tbin->slots[tbin->ncached]); } static void -mag_load(mag_t *mag) +tcache_bin_fill(tcache_t *tcache, tcache_bin_t *tbin, size_t binind) { arena_t *arena; arena_bin_t *bin; arena_run_t *run; - void *round; - size_t i; + void *ptr; + unsigned i; - arena = choose_arena(); - bin = &arena->bins[mag->binind]; -#ifdef MALLOC_BALANCE - arena_lock_balance(arena); -#else + assert(tbin->ncached == 0); + + arena = tcache->arena; + bin = &arena->bins[binind]; malloc_spin_lock(&arena->lock); -#endif - for (i = mag->nrounds; i < max_rounds; i++) { + for (i = 0; i < (tcache_nslots >> 1); i++) { if ((run = bin->runcur) != NULL && run->nfree > 0) - round = arena_bin_malloc_easy(arena, bin, run); + ptr = arena_bin_malloc_easy(arena, bin, run); else - round = arena_bin_malloc_hard(arena, bin); - if (round == NULL) + ptr = arena_bin_malloc_hard(arena, bin); + if (ptr == NULL) break; - mag->rounds[i] = round; + /* + * Fill tbin such that the objects lowest in memory are used + * first. + */ + tbin->slots[(tcache_nslots >> 1) - 1 - i] = ptr; } #ifdef MALLOC_STATS - bin->stats.nmags++; - arena->stats.nmalloc_small += (i - mag->nrounds); - arena->stats.allocated_small += (i - mag->nrounds) * bin->reg_size; + bin->stats.nfills++; + bin->stats.nrequests += tbin->tstats.nrequests; + if (bin->reg_size <= small_maxclass) { + arena->stats.nmalloc_small += (i - tbin->ncached); + arena->stats.allocated_small += (i - tbin->ncached) * + bin->reg_size; + arena->stats.nmalloc_small += tbin->tstats.nrequests; + } else { + arena->stats.nmalloc_medium += (i - tbin->ncached); + arena->stats.allocated_medium += (i - tbin->ncached) * + bin->reg_size; + arena->stats.nmalloc_medium += tbin->tstats.nrequests; + } + tbin->tstats.nrequests = 0; #endif malloc_spin_unlock(&arena->lock); - mag->nrounds = i; + tbin->ncached = i; + if (tbin->ncached > tbin->high_water) + tbin->high_water = tbin->ncached; } static inline void * -mag_rack_alloc(mag_rack_t *rack, size_t size, bool zero) +tcache_alloc(tcache_t *tcache, size_t size, bool zero) { void *ret; - bin_mags_t *bin_mags; - mag_t *mag; + tcache_bin_t *tbin; size_t binind; - binind = size2bin[size]; + if (size <= small_maxclass) + binind = small_size2bin[size]; + else { + binind = mbin0 + ((MEDIUM_CEILING(size) - medium_min) >> + lg_mspace); + } assert(binind < nbins); - bin_mags = &rack->bin_mags[binind]; - - mag = bin_mags->curmag; - if (mag == NULL) { - /* Create an initial magazine for this size class. */ - assert(bin_mags->sparemag == NULL); - mag = mag_create(choose_arena(), binind); - if (mag == NULL) + tbin = tcache->tbins[binind]; + if (tbin == NULL) { + tbin = tcache_bin_create(tcache->arena); + if (tbin == NULL) return (NULL); - bin_mags->curmag = mag; - mag_load(mag); + tcache->tbins[binind] = tbin; } - ret = mag_alloc(mag); + ret = tcache_bin_alloc(tbin); if (ret == NULL) { - if (bin_mags->sparemag != NULL) { - if (bin_mags->sparemag->nrounds > 0) { - /* Swap magazines. */ - bin_mags->curmag = bin_mags->sparemag; - bin_mags->sparemag = mag; - mag = bin_mags->curmag; - } else { - /* Reload the current magazine. */ - mag_load(mag); - } - } else { - /* Create a second magazine. */ - mag = mag_create(choose_arena(), binind); - if (mag == NULL) - return (NULL); - mag_load(mag); - bin_mags->sparemag = bin_mags->curmag; - bin_mags->curmag = mag; - } - ret = mag_alloc(mag); + ret = tcache_alloc_hard(tcache, tbin, binind); if (ret == NULL) return (NULL); } @@ -3196,6 +3394,21 @@ mag_rack_alloc(mag_rack_t *rack, size_t size, bool zero) } else memset(ret, 0, size); +#ifdef MALLOC_STATS + tbin->tstats.nrequests++; +#endif + tcache_event(tcache); + return (ret); +} + +static void * +tcache_alloc_hard(tcache_t *tcache, tcache_bin_t *tbin, size_t binind) +{ + void *ret; + + tcache_bin_fill(tcache, tbin, binind); + ret = tcache_bin_alloc(tbin); + return (ret); } #endif @@ -3208,16 +3421,12 @@ arena_malloc_small(arena_t *arena, size_t size, bool zero) arena_run_t *run; size_t binind; - binind = size2bin[size]; - assert(binind < nbins); + binind = small_size2bin[size]; + assert(binind < mbin0); bin = &arena->bins[binind]; size = bin->reg_size; -#ifdef MALLOC_BALANCE - arena_lock_balance(arena); -#else malloc_spin_lock(&arena->lock); -#endif if ((run = bin->runcur) != NULL && run->nfree > 0) ret = arena_bin_malloc_easy(arena, bin, run); else @@ -3229,8 +3438,14 @@ arena_malloc_small(arena_t *arena, size_t size, bool zero) } #ifdef MALLOC_STATS - bin->stats.nrequests++; - arena->stats.nmalloc_small++; +# ifdef MALLOC_TCACHE + if (__isthreaded == false) { +# endif + bin->stats.nrequests++; + arena->stats.nmalloc_small++; +# ifdef MALLOC_TCACHE + } +# endif arena->stats.allocated_small += size; #endif malloc_spin_unlock(&arena->lock); @@ -3247,17 +3462,62 @@ arena_malloc_small(arena_t *arena, size_t size, bool zero) } static void * +arena_malloc_medium(arena_t *arena, size_t size, bool zero) +{ + void *ret; + arena_bin_t *bin; + arena_run_t *run; + size_t binind; + + size = MEDIUM_CEILING(size); + binind = mbin0 + ((size - medium_min) >> lg_mspace); + assert(binind < nbins); + bin = &arena->bins[binind]; + assert(bin->reg_size == size); + + malloc_spin_lock(&arena->lock); + if ((run = bin->runcur) != NULL && run->nfree > 0) + ret = arena_bin_malloc_easy(arena, bin, run); + else + ret = arena_bin_malloc_hard(arena, bin); + + if (ret == NULL) { + malloc_spin_unlock(&arena->lock); + return (NULL); + } + +#ifdef MALLOC_STATS +# ifdef MALLOC_TCACHE + if (__isthreaded == false) { +# endif + bin->stats.nrequests++; + arena->stats.nmalloc_medium++; +# ifdef MALLOC_TCACHE + } +# endif + arena->stats.allocated_medium += size; +#endif + malloc_spin_unlock(&arena->lock); + + if (zero == false) { + if (opt_junk) + memset(ret, 0xa5, size); + else if (opt_zero) + memset(ret, 0, size); + } else + memset(ret, 0, size); + + return (ret); +} + +static void * arena_malloc_large(arena_t *arena, size_t size, bool zero) { void *ret; /* Large allocation. */ size = PAGE_CEILING(size); -#ifdef MALLOC_BALANCE - arena_lock_balance(arena); -#else malloc_spin_lock(&arena->lock); -#endif ret = (void *)arena_run_alloc(arena, size, true, zero); if (ret == NULL) { malloc_spin_unlock(&arena->lock); @@ -3266,6 +3526,13 @@ arena_malloc_large(arena_t *arena, size_t size, bool zero) #ifdef MALLOC_STATS arena->stats.nmalloc_large++; arena->stats.allocated_large += size; + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].nrequests++; + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns++; + if (arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns > + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].highruns) { + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].highruns = + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns; + } #endif malloc_spin_unlock(&arena->lock); @@ -3280,30 +3547,35 @@ arena_malloc_large(arena_t *arena, size_t size, bool zero) } static inline void * -arena_malloc(arena_t *arena, size_t size, bool zero) +arena_malloc(size_t size, bool zero) { - assert(arena != NULL); - assert(arena->magic == ARENA_MAGIC); assert(size != 0); assert(QUANTUM_CEILING(size) <= arena_maxclass); if (size <= bin_maxclass) { -#ifdef MALLOC_MAG - if (__isthreaded && opt_mag) { - mag_rack_t *rack = mag_rack; - if (rack == NULL) { - rack = mag_rack_create(arena); - if (rack == NULL) +#ifdef MALLOC_TCACHE + if (__isthreaded && tcache_nslots) { + tcache_t *tcache = tcache_tls; + if ((uintptr_t)tcache > (uintptr_t)1) + return (tcache_alloc(tcache, size, zero)); + else if (tcache == NULL) { + tcache = tcache_create(choose_arena()); + if (tcache == NULL) return (NULL); - mag_rack = rack; + return (tcache_alloc(tcache, size, zero)); } - return (mag_rack_alloc(rack, size, zero)); - } else + } #endif - return (arena_malloc_small(arena, size, zero)); + if (size <= small_maxclass) { + return (arena_malloc_small(choose_arena(), size, + zero)); + } else { + return (arena_malloc_medium(choose_arena(), + size, zero)); + } } else - return (arena_malloc_large(arena, size, zero)); + return (arena_malloc_large(choose_arena(), size, zero)); } static inline void * @@ -3313,7 +3585,7 @@ imalloc(size_t size) assert(size != 0); if (size <= arena_maxclass) - return (arena_malloc(choose_arena(), size, false)); + return (arena_malloc(size, false)); else return (huge_malloc(size, false)); } @@ -3323,7 +3595,7 @@ icalloc(size_t size) { if (size <= arena_maxclass) - return (arena_malloc(choose_arena(), size, true)); + return (arena_malloc(size, true)); else return (huge_malloc(size, true)); } @@ -3339,11 +3611,7 @@ arena_palloc(arena_t *arena, size_t alignment, size_t size, size_t alloc_size) assert((size & PAGE_MASK) == 0); assert((alignment & PAGE_MASK) == 0); -#ifdef MALLOC_BALANCE - arena_lock_balance(arena); -#else malloc_spin_lock(&arena->lock); -#endif ret = (void *)arena_run_alloc(arena, alloc_size, true, false); if (ret == NULL) { malloc_spin_unlock(&arena->lock); @@ -3379,6 +3647,13 @@ arena_palloc(arena_t *arena, size_t alignment, size_t size, size_t alloc_size) #ifdef MALLOC_STATS arena->stats.nmalloc_large++; arena->stats.allocated_large += size; + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].nrequests++; + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns++; + if (arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns > + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].highruns) { + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].highruns = + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns; + } #endif malloc_spin_unlock(&arena->lock); @@ -3425,7 +3700,7 @@ ipalloc(size_t alignment, size_t size) if (ceil_size <= PAGE_SIZE || (alignment <= PAGE_SIZE && ceil_size <= arena_maxclass)) - ret = arena_malloc(choose_arena(), ceil_size, false); + ret = arena_malloc(ceil_size, false); else { size_t run_size; @@ -3484,6 +3759,22 @@ ipalloc(size_t alignment, size_t size) return (ret); } +static bool +arena_is_large(const void *ptr) +{ + arena_chunk_t *chunk; + size_t pageind, mapbits; + + assert(ptr != NULL); + assert(CHUNK_ADDR2BASE(ptr) != ptr); + + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); + pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT); + mapbits = chunk->map[pageind].bits; + assert((mapbits & CHUNK_MAP_ALLOCATED) != 0); + return ((mapbits & CHUNK_MAP_LARGE) != 0); +} + /* Return the size of the allocation pointed to by ptr. */ static size_t arena_salloc(const void *ptr) @@ -3500,7 +3791,9 @@ arena_salloc(const void *ptr) mapbits = chunk->map[pageind].bits; assert((mapbits & CHUNK_MAP_ALLOCATED) != 0); if ((mapbits & CHUNK_MAP_LARGE) == 0) { - arena_run_t *run = (arena_run_t *)(mapbits & ~PAGE_MASK); + arena_run_t *run = (arena_run_t *)((uintptr_t)chunk + + (uintptr_t)((pageind - ((mapbits & CHUNK_MAP_PG_MASK) >> + CHUNK_MAP_PG_SHIFT)) << PAGE_SHIFT)); assert(run->magic == ARENA_RUN_MAGIC); ret = run->bin->reg_size; } else { @@ -3546,14 +3839,18 @@ isalloc(const void *ptr) } static inline void -arena_dalloc_small(arena_t *arena, arena_chunk_t *chunk, void *ptr, +arena_dalloc_bin(arena_t *arena, arena_chunk_t *chunk, void *ptr, arena_chunk_map_t *mapelm) { + size_t pageind; arena_run_t *run; arena_bin_t *bin; size_t size; - run = (arena_run_t *)(mapelm->bits & ~PAGE_MASK); + pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT); + run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind - + ((mapelm->bits & CHUNK_MAP_PG_MASK) >> CHUNK_MAP_PG_SHIFT)) << + PAGE_SHIFT)); assert(run->magic == ARENA_RUN_MAGIC); bin = run->bin; size = bin->reg_size; @@ -3564,30 +3861,9 @@ arena_dalloc_small(arena_t *arena, arena_chunk_t *chunk, void *ptr, arena_run_reg_dalloc(run, bin, ptr, size); run->nfree++; - if (run->nfree == bin->nregs) { - /* Deallocate run. */ - if (run == bin->runcur) - bin->runcur = NULL; - else if (bin->nregs != 1) { - size_t run_pageind = (((uintptr_t)run - - (uintptr_t)chunk)) >> PAGE_SHIFT; - arena_chunk_map_t *run_mapelm = - &chunk->map[run_pageind]; - /* - * This block's conditional is necessary because if the - * run only contains one region, then it never gets - * inserted into the non-full runs tree. - */ - arena_run_tree_remove(&bin->runs, run_mapelm); - } -#ifdef MALLOC_DEBUG - run->magic = 0; -#endif - arena_run_dalloc(arena, run, true); -#ifdef MALLOC_STATS - bin->stats.curruns--; -#endif - } else if (run->nfree == 1 && run != bin->runcur) { + if (run->nfree == bin->nregs) + arena_dalloc_bin_run(arena, chunk, run, bin); + else if (run->nfree == 1 && run != bin->runcur) { /* * Make sure that bin->runcur always refers to the lowest * non-full run, if one exists. @@ -3621,67 +3897,297 @@ arena_dalloc_small(arena_t *arena, arena_chunk_t *chunk, void *ptr, arena_run_tree_insert(&bin->runs, run_mapelm); } } + +#ifdef MALLOC_STATS + if (size <= small_maxclass) { + arena->stats.allocated_small -= size; + arena->stats.ndalloc_small++; + } else { + arena->stats.allocated_medium -= size; + arena->stats.ndalloc_medium++; + } +#endif +} + +static void +arena_dalloc_bin_run(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run, + arena_bin_t *bin) +{ + size_t run_ind; + + /* Deallocate run. */ + if (run == bin->runcur) + bin->runcur = NULL; + else if (bin->nregs != 1) { + size_t run_pageind = (((uintptr_t)run - + (uintptr_t)chunk)) >> PAGE_SHIFT; + arena_chunk_map_t *run_mapelm = + &chunk->map[run_pageind]; + /* + * This block's conditional is necessary because if the + * run only contains one region, then it never gets + * inserted into the non-full runs tree. + */ + arena_run_tree_remove(&bin->runs, run_mapelm); + } + /* + * Mark the first page as dirty. The dirty bit for every other page in + * the run is already properly set, which means we can call + * arena_run_dalloc(..., false), thus potentially avoiding the needless + * creation of many dirty pages. + */ + run_ind = (size_t)(((uintptr_t)run - (uintptr_t)chunk) >> PAGE_SHIFT); + assert((chunk->map[run_ind].bits & CHUNK_MAP_DIRTY) == 0); + chunk->map[run_ind].bits |= CHUNK_MAP_DIRTY; + chunk->ndirty++; + arena->ndirty++; + +#ifdef MALLOC_DEBUG + run->magic = 0; +#endif + arena_run_dalloc(arena, run, false); +#ifdef MALLOC_STATS + bin->stats.curruns--; +#endif + + if (chunk->dirtied == false) { + arena_chunk_tree_dirty_insert(&arena->chunks_dirty, chunk); + chunk->dirtied = true; + } + /* Enforce opt_lg_dirty_mult. */ + if (opt_lg_dirty_mult >= 0 && (arena->nactive >> opt_lg_dirty_mult) < + arena->ndirty) + arena_purge(arena); +} + #ifdef MALLOC_STATS - arena->stats.allocated_small -= size; - arena->stats.ndalloc_small++; +static void +arena_stats_print(arena_t *arena) +{ + + malloc_printf("dirty pages: %zu:%zu active:dirty, %"PRIu64" sweep%s," + " %"PRIu64" madvise%s, %"PRIu64" purged\n", + arena->nactive, arena->ndirty, + arena->stats.npurge, arena->stats.npurge == 1 ? "" : "s", + arena->stats.nmadvise, arena->stats.nmadvise == 1 ? "" : "s", + arena->stats.purged); + + malloc_printf(" allocated nmalloc ndalloc\n"); + malloc_printf("small: %12zu %12"PRIu64" %12"PRIu64"\n", + arena->stats.allocated_small, arena->stats.nmalloc_small, + arena->stats.ndalloc_small); + malloc_printf("medium: %12zu %12"PRIu64" %12"PRIu64"\n", + arena->stats.allocated_medium, arena->stats.nmalloc_medium, + arena->stats.ndalloc_medium); + malloc_printf("large: %12zu %12"PRIu64" %12"PRIu64"\n", + arena->stats.allocated_large, arena->stats.nmalloc_large, + arena->stats.ndalloc_large); + malloc_printf("total: %12zu %12"PRIu64" %12"PRIu64"\n", + arena->stats.allocated_small + arena->stats.allocated_medium + + arena->stats.allocated_large, arena->stats.nmalloc_small + + arena->stats.nmalloc_medium + arena->stats.nmalloc_large, + arena->stats.ndalloc_small + arena->stats.ndalloc_medium + + arena->stats.ndalloc_large); + malloc_printf("mapped: %12zu\n", arena->stats.mapped); + + if (arena->stats.nmalloc_small + arena->stats.nmalloc_medium > 0) { + unsigned i, gap_start; +#ifdef MALLOC_TCACHE + malloc_printf("bins: bin size regs pgs requests " + "nfills nflushes newruns reruns maxruns curruns\n"); +#else + malloc_printf("bins: bin size regs pgs requests " + "newruns reruns maxruns curruns\n"); +#endif + for (i = 0, gap_start = UINT_MAX; i < nbins; i++) { + if (arena->bins[i].stats.nruns == 0) { + if (gap_start == UINT_MAX) + gap_start = i; + } else { + if (gap_start != UINT_MAX) { + if (i > gap_start + 1) { + /* + * Gap of more than one size + * class. + */ + malloc_printf("[%u..%u]\n", + gap_start, i - 1); + } else { + /* Gap of one size class. */ + malloc_printf("[%u]\n", + gap_start); + } + gap_start = UINT_MAX; + } + malloc_printf( + "%13u %1s %5u %4u %3u %9"PRIu64" %9"PRIu64 +#ifdef MALLOC_TCACHE + " %9"PRIu64" %9"PRIu64 +#endif + " %9"PRIu64" %7zu %7zu\n", + i, + i < ntbins ? "T" : i < ntbins + nqbins ? + "Q" : i < ntbins + nqbins + ncbins ? "C" : + i < ntbins + nqbins + ncbins + nsbins ? "S" + : "M", + arena->bins[i].reg_size, + arena->bins[i].nregs, + arena->bins[i].run_size >> PAGE_SHIFT, + arena->bins[i].stats.nrequests, +#ifdef MALLOC_TCACHE + arena->bins[i].stats.nfills, + arena->bins[i].stats.nflushes, +#endif + arena->bins[i].stats.nruns, + arena->bins[i].stats.reruns, + arena->bins[i].stats.highruns, + arena->bins[i].stats.curruns); + } + } + if (gap_start != UINT_MAX) { + if (i > gap_start + 1) { + /* Gap of more than one size class. */ + malloc_printf("[%u..%u]\n", gap_start, i - 1); + } else { + /* Gap of one size class. */ + malloc_printf("[%u]\n", gap_start); + } + } + } + + if (arena->stats.nmalloc_large > 0) { + size_t i; + ssize_t gap_start; + size_t nlclasses = (chunksize - PAGE_SIZE) >> PAGE_SHIFT; + + malloc_printf( + "large: size pages nrequests maxruns curruns\n"); + + for (i = 0, gap_start = -1; i < nlclasses; i++) { + if (arena->stats.lstats[i].nrequests == 0) { + if (gap_start == -1) + gap_start = i; + } else { + if (gap_start != -1) { + malloc_printf("[%zu]\n", i - gap_start); + gap_start = -1; + } + malloc_printf( + "%13zu %5zu %9"PRIu64" %9zu %9zu\n", + (i+1) << PAGE_SHIFT, i+1, + arena->stats.lstats[i].nrequests, + arena->stats.lstats[i].highruns, + arena->stats.lstats[i].curruns); + } + } + if (gap_start != -1) + malloc_printf("[%zu]\n", i - gap_start); + } +} +#endif + +static void +stats_print_atexit(void) +{ + +#if (defined(MALLOC_TCACHE) && defined(MALLOC_STATS)) + unsigned i; + + /* + * Merge stats from extant threads. This is racy, since individual + * threads do not lock when recording tcache stats events. As a + * consequence, the final stats may be slightly out of date by the time + * they are reported, if other threads continue to allocate. + */ + for (i = 0; i < narenas; i++) { + arena_t *arena = arenas[i]; + if (arena != NULL) { + tcache_t *tcache; + + malloc_spin_lock(&arena->lock); + ql_foreach(tcache, &arena->tcache_ql, link) { + tcache_stats_merge(tcache, arena); + } + malloc_spin_unlock(&arena->lock); + } + } #endif + malloc_stats_print(); } -#ifdef MALLOC_MAG +#ifdef MALLOC_TCACHE static void -mag_unload(mag_t *mag) +tcache_bin_flush(tcache_bin_t *tbin, size_t binind, unsigned rem) { arena_chunk_t *chunk; arena_t *arena; - void *round; - size_t i, ndeferred, nrounds; + void *ptr; + unsigned i, ndeferred, ncached; - for (ndeferred = mag->nrounds; ndeferred > 0;) { - nrounds = ndeferred; - /* Lock the arena associated with the first round. */ - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(mag->rounds[0]); + for (ndeferred = tbin->ncached - rem; ndeferred > 0;) { + ncached = ndeferred; + /* Lock the arena associated with the first object. */ + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(tbin->slots[0]); arena = chunk->arena; -#ifdef MALLOC_BALANCE - arena_lock_balance(arena); -#else malloc_spin_lock(&arena->lock); -#endif - /* Deallocate every round that belongs to the locked arena. */ - for (i = ndeferred = 0; i < nrounds; i++) { - round = mag->rounds[i]; - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(round); + /* Deallocate every object that belongs to the locked arena. */ + for (i = ndeferred = 0; i < ncached; i++) { + ptr = tbin->slots[i]; + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); if (chunk->arena == arena) { - size_t pageind = (((uintptr_t)round - + size_t pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT); arena_chunk_map_t *mapelm = &chunk->map[pageind]; - arena_dalloc_small(arena, chunk, round, mapelm); + arena_dalloc_bin(arena, chunk, ptr, mapelm); } else { /* - * This round was allocated via a different + * This object was allocated via a different * arena than the one that is currently locked. - * Stash the round, so that it can be handled + * Stash the object, so that it can be handled * in a future pass. */ - mag->rounds[ndeferred] = round; + tbin->slots[ndeferred] = ptr; ndeferred++; } } +#ifdef MALLOC_STATS + arena->bins[binind].stats.nflushes++; + { + arena_bin_t *bin = &arena->bins[binind]; + bin->stats.nrequests += tbin->tstats.nrequests; + if (bin->reg_size <= small_maxclass) { + arena->stats.nmalloc_small += + tbin->tstats.nrequests; + } else { + arena->stats.nmalloc_medium += + tbin->tstats.nrequests; + } + tbin->tstats.nrequests = 0; + } +#endif malloc_spin_unlock(&arena->lock); } - mag->nrounds = 0; + if (rem > 0) { + /* + * Shift the remaining valid pointers to the base of the slots + * array. + */ + memmove(&tbin->slots[0], &tbin->slots[tbin->ncached - rem], + rem * sizeof(void *)); + } + tbin->ncached = rem; } static inline void -mag_rack_dalloc(mag_rack_t *rack, void *ptr) +tcache_dalloc(tcache_t *tcache, void *ptr) { arena_t *arena; arena_chunk_t *chunk; arena_run_t *run; arena_bin_t *bin; - bin_mags_t *bin_mags; - mag_t *mag; + tcache_bin_t *tbin; size_t pageind, binind; arena_chunk_map_t *mapelm; @@ -3689,7 +4195,9 @@ mag_rack_dalloc(mag_rack_t *rack, void *ptr) arena = chunk->arena; pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT); mapelm = &chunk->map[pageind]; - run = (arena_run_t *)(mapelm->bits & ~PAGE_MASK); + run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind - + ((mapelm->bits & CHUNK_MAP_PG_MASK) >> CHUNK_MAP_PG_SHIFT)) << + PAGE_SHIFT)); assert(run->magic == ARENA_RUN_MAGIC); bin = run->bin; binind = ((uintptr_t)bin - (uintptr_t)&arena->bins) / @@ -3699,53 +4207,34 @@ mag_rack_dalloc(mag_rack_t *rack, void *ptr) if (opt_junk) memset(ptr, 0x5a, arena->bins[binind].reg_size); - bin_mags = &rack->bin_mags[binind]; - mag = bin_mags->curmag; - if (mag == NULL) { - /* Create an initial magazine for this size class. */ - assert(bin_mags->sparemag == NULL); - mag = mag_create(choose_arena(), binind); - if (mag == NULL) { - malloc_spin_lock(&arena->lock); - arena_dalloc_small(arena, chunk, ptr, mapelm); - malloc_spin_unlock(&arena->lock); - return; - } - bin_mags->curmag = mag; - } - - if (mag->nrounds == max_rounds) { - if (bin_mags->sparemag != NULL) { - if (bin_mags->sparemag->nrounds < max_rounds) { - /* Swap magazines. */ - bin_mags->curmag = bin_mags->sparemag; - bin_mags->sparemag = mag; - mag = bin_mags->curmag; - } else { - /* Unload the current magazine. */ - mag_unload(mag); - } - } else { - /* Create a second magazine. */ - mag = mag_create(choose_arena(), binind); - if (mag == NULL) { - mag = rack->bin_mags[binind].curmag; - mag_unload(mag); - } else { - bin_mags->sparemag = bin_mags->curmag; - bin_mags->curmag = mag; - } + tbin = tcache->tbins[binind]; + if (tbin == NULL) { + tbin = tcache_bin_create(choose_arena()); + if (tbin == NULL) { + malloc_spin_lock(&arena->lock); + arena_dalloc_bin(arena, chunk, ptr, mapelm); + malloc_spin_unlock(&arena->lock); + return; } - assert(mag->nrounds < max_rounds); + tcache->tbins[binind] = tbin; } - mag->rounds[mag->nrounds] = ptr; - mag->nrounds++; + + if (tbin->ncached == tcache_nslots) + tcache_bin_flush(tbin, binind, (tcache_nslots >> 1)); + assert(tbin->ncached < tcache_nslots); + tbin->slots[tbin->ncached] = ptr; + tbin->ncached++; + if (tbin->ncached > tbin->high_water) + tbin->high_water = tbin->ncached; + + tcache_event(tcache); } #endif static void arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk, void *ptr) { + /* Large allocation. */ malloc_spin_lock(&arena->lock); @@ -3762,12 +4251,11 @@ arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk, void *ptr) #endif memset(ptr, 0x5a, size); #ifdef MALLOC_STATS + arena->stats.ndalloc_large++; arena->stats.allocated_large -= size; + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns--; #endif } -#ifdef MALLOC_STATS - arena->stats.ndalloc_large++; -#endif arena_run_dalloc(arena, (arena_run_t *)ptr, true); malloc_spin_unlock(&arena->lock); @@ -3790,33 +4278,51 @@ arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr) assert((mapelm->bits & CHUNK_MAP_ALLOCATED) != 0); if ((mapelm->bits & CHUNK_MAP_LARGE) == 0) { /* Small allocation. */ -#ifdef MALLOC_MAG - if (__isthreaded && opt_mag) { - mag_rack_t *rack = mag_rack; - if (rack == NULL) { - rack = mag_rack_create(arena); - if (rack == NULL) { - malloc_spin_lock(&arena->lock); - arena_dalloc_small(arena, chunk, ptr, - mapelm); - malloc_spin_unlock(&arena->lock); - return; - } - mag_rack = rack; +#ifdef MALLOC_TCACHE + if (__isthreaded && tcache_nslots) { + tcache_t *tcache = tcache_tls; + if ((uintptr_t)tcache > (uintptr_t)1) + tcache_dalloc(tcache, ptr); + else { + arena_dalloc_hard(arena, chunk, ptr, mapelm, + tcache); } - mag_rack_dalloc(rack, ptr); } else { #endif malloc_spin_lock(&arena->lock); - arena_dalloc_small(arena, chunk, ptr, mapelm); + arena_dalloc_bin(arena, chunk, ptr, mapelm); malloc_spin_unlock(&arena->lock); -#ifdef MALLOC_MAG +#ifdef MALLOC_TCACHE } #endif } else arena_dalloc_large(arena, chunk, ptr); } +#ifdef MALLOC_TCACHE +static void +arena_dalloc_hard(arena_t *arena, arena_chunk_t *chunk, void *ptr, + arena_chunk_map_t *mapelm, tcache_t *tcache) +{ + + if (tcache == NULL) { + tcache = tcache_create(arena); + if (tcache == NULL) { + malloc_spin_lock(&arena->lock); + arena_dalloc_bin(arena, chunk, ptr, mapelm); + malloc_spin_unlock(&arena->lock); + } else + tcache_dalloc(tcache, ptr); + } else { + /* This thread is currently exiting, so directly deallocate. */ + assert(tcache == (void *)(uintptr_t)1); + malloc_spin_lock(&arena->lock); + arena_dalloc_bin(arena, chunk, ptr, mapelm); + malloc_spin_unlock(&arena->lock); + } +} +#endif + static inline void idalloc(void *ptr) { @@ -3842,15 +4348,23 @@ arena_ralloc_large_shrink(arena_t *arena, arena_chunk_t *chunk, void *ptr, * Shrink the run, and make trailing pages available for other * allocations. */ -#ifdef MALLOC_BALANCE - arena_lock_balance(arena); -#else malloc_spin_lock(&arena->lock); -#endif arena_run_trim_tail(arena, chunk, (arena_run_t *)ptr, oldsize, size, true); #ifdef MALLOC_STATS - arena->stats.allocated_large -= oldsize - size; + arena->stats.ndalloc_large++; + arena->stats.allocated_large -= oldsize; + arena->stats.lstats[(oldsize >> PAGE_SHIFT) - 1].curruns--; + + arena->stats.nmalloc_large++; + arena->stats.allocated_large += size; + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].nrequests++; + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns++; + if (arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns > + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].highruns) { + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].highruns = + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns; + } #endif malloc_spin_unlock(&arena->lock); } @@ -3866,11 +4380,7 @@ arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr, /* Try to extend the run. */ assert(size > oldsize); -#ifdef MALLOC_BALANCE - arena_lock_balance(arena); -#else malloc_spin_lock(&arena->lock); -#endif if (pageind + npages < chunk_npages && (chunk->map[pageind+npages].bits & CHUNK_MAP_ALLOCATED) == 0 && (chunk->map[pageind+npages].bits & ~PAGE_MASK) >= size - oldsize) { @@ -3889,7 +4399,19 @@ arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr, CHUNK_MAP_ALLOCATED; #ifdef MALLOC_STATS - arena->stats.allocated_large += size - oldsize; + arena->stats.ndalloc_large++; + arena->stats.allocated_large -= oldsize; + arena->stats.lstats[(oldsize >> PAGE_SHIFT) - 1].curruns--; + + arena->stats.nmalloc_large++; + arena->stats.allocated_large += size; + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].nrequests++; + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns++; + if (arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns > + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].highruns) { + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].highruns = + arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns; + } #endif malloc_spin_unlock(&arena->lock); return (false); @@ -3951,13 +4473,48 @@ arena_ralloc(void *ptr, size_t size, size_t oldsize) void *ret; size_t copysize; + /* + * Try to avoid moving the allocation. + * + * posix_memalign() can cause allocation of "large" objects that are + * smaller than bin_maxclass (in order to meet alignment requirements). + * Therefore, do not assume that (oldsize <= bin_maxclass) indicates + * ptr refers to a bin-allocated object. + */ + if (oldsize <= arena_maxclass) { + if (arena_is_large(ptr) == false ) { + if (size <= small_maxclass) { + if (oldsize <= small_maxclass && + small_size2bin[size] == + small_size2bin[oldsize]) + goto IN_PLACE; + } else if (size <= bin_maxclass) { + if (small_maxclass < oldsize && oldsize <= + bin_maxclass && MEDIUM_CEILING(size) == + MEDIUM_CEILING(oldsize)) + goto IN_PLACE; + } + } else { + assert(size <= arena_maxclass); + if (size > bin_maxclass) { + if (arena_ralloc_large(ptr, size, oldsize) == + false) + return (ptr); + } + } + } + /* Try to avoid moving the allocation. */ - if (size <= bin_maxclass) { - if (oldsize <= bin_maxclass && size2bin[size] == - size2bin[oldsize]) + if (size <= small_maxclass) { + if (oldsize <= small_maxclass && small_size2bin[size] == + small_size2bin[oldsize]) + goto IN_PLACE; + } else if (size <= bin_maxclass) { + if (small_maxclass < oldsize && oldsize <= bin_maxclass && + MEDIUM_CEILING(size) == MEDIUM_CEILING(oldsize)) goto IN_PLACE; } else { - if (oldsize > bin_maxclass && oldsize <= arena_maxclass) { + if (bin_maxclass < oldsize && oldsize <= arena_maxclass) { assert(size > bin_maxclass); if (arena_ralloc_large(ptr, size, oldsize) == false) return (ptr); @@ -3969,7 +4526,7 @@ arena_ralloc(void *ptr, size_t size, size_t oldsize) * need to move the object. In that case, fall back to allocating new * space and copying. */ - ret = arena_malloc(choose_arena(), size, false); + ret = arena_malloc(size, false); if (ret == NULL) return (NULL); @@ -4003,7 +4560,7 @@ iralloc(void *ptr, size_t size) } static bool -arena_new(arena_t *arena) +arena_new(arena_t *arena, unsigned ind) { unsigned i; arena_bin_t *bin; @@ -4014,20 +4571,27 @@ arena_new(arena_t *arena) #ifdef MALLOC_STATS memset(&arena->stats, 0, sizeof(arena_stats_t)); + arena->stats.lstats = (malloc_large_stats_t *)base_alloc( + sizeof(malloc_large_stats_t) * ((chunksize - PAGE_SIZE) >> + PAGE_SHIFT)); + if (arena->stats.lstats == NULL) + return (true); + memset(arena->stats.lstats, 0, sizeof(malloc_large_stats_t) * + ((chunksize - PAGE_SIZE) >> PAGE_SHIFT)); +# ifdef MALLOC_TCACHE + ql_new(&arena->tcache_ql); +# endif #endif /* Initialize chunks. */ arena_chunk_tree_dirty_new(&arena->chunks_dirty); arena->spare = NULL; + arena->nactive = 0; arena->ndirty = 0; arena_avail_tree_new(&arena->runs_avail); -#ifdef MALLOC_BALANCE - arena->contention = 0; -#endif - /* Initialize bins. */ prev_run_size = PAGE_SIZE; @@ -4039,7 +4603,7 @@ arena_new(arena_t *arena) bin->runcur = NULL; arena_run_tree_new(&bin->runs); - bin->reg_size = (1U << (TINY_MIN_2POW + i)); + bin->reg_size = (1U << (LG_TINY_MIN + i)); prev_run_size = arena_bin_run_size_calc(bin, prev_run_size); @@ -4055,7 +4619,7 @@ arena_new(arena_t *arena) bin->runcur = NULL; arena_run_tree_new(&bin->runs); - bin->reg_size = (i - ntbins + 1) << QUANTUM_2POW; + bin->reg_size = (i - ntbins + 1) << LG_QUANTUM; prev_run_size = arena_bin_run_size_calc(bin, prev_run_size); @@ -4071,7 +4635,7 @@ arena_new(arena_t *arena) arena_run_tree_new(&bin->runs); bin->reg_size = cspace_min + ((i - (ntbins + nqbins)) << - CACHELINE_2POW); + LG_CACHELINE); prev_run_size = arena_bin_run_size_calc(bin, prev_run_size); @@ -4081,13 +4645,29 @@ arena_new(arena_t *arena) } /* Subpage-spaced bins. */ - for (; i < nbins; i++) { + for (; i < ntbins + nqbins + ncbins + nsbins; i++) { bin = &arena->bins[i]; bin->runcur = NULL; arena_run_tree_new(&bin->runs); bin->reg_size = sspace_min + ((i - (ntbins + nqbins + ncbins)) - << SUBPAGE_2POW); + << LG_SUBPAGE); + + prev_run_size = arena_bin_run_size_calc(bin, prev_run_size); + +#ifdef MALLOC_STATS + memset(&bin->stats, 0, sizeof(malloc_bin_stats_t)); +#endif + } + + /* Medium bins. */ + for (; i < nbins; i++) { + bin = &arena->bins[i]; + bin->runcur = NULL; + arena_run_tree_new(&bin->runs); + + bin->reg_size = medium_min + ((i - (ntbins + nqbins + ncbins + + nsbins)) << lg_mspace); prev_run_size = arena_bin_run_size_calc(bin, prev_run_size); @@ -4112,7 +4692,7 @@ arenas_extend(unsigned ind) /* Allocate enough space for trailing bins. */ ret = (arena_t *)base_alloc(sizeof(arena_t) + (sizeof(arena_bin_t) * (nbins - 1))); - if (ret != NULL && arena_new(ret) == false) { + if (ret != NULL && arena_new(ret, ind) == false) { arenas[ind] = ret; return (ret); } @@ -4132,92 +4712,166 @@ arenas_extend(unsigned ind) return (arenas[0]); } -#ifdef MALLOC_MAG -static mag_t * -mag_create(arena_t *arena, size_t binind) +#ifdef MALLOC_TCACHE +static tcache_bin_t * +tcache_bin_create(arena_t *arena) { - mag_t *ret; - - if (sizeof(mag_t) + (sizeof(void *) * (max_rounds - 1)) <= - bin_maxclass) { - ret = arena_malloc_small(arena, sizeof(mag_t) + (sizeof(void *) - * (max_rounds - 1)), false); - } else { - ret = imalloc(sizeof(mag_t) + (sizeof(void *) * (max_rounds - - 1))); - } + tcache_bin_t *ret; + size_t tsize; + + tsize = sizeof(tcache_bin_t) + (sizeof(void *) * (tcache_nslots - 1)); + if (tsize <= small_maxclass) + ret = (tcache_bin_t *)arena_malloc_small(arena, tsize, false); + else if (tsize <= bin_maxclass) + ret = (tcache_bin_t *)arena_malloc_medium(arena, tsize, false); + else + ret = (tcache_bin_t *)imalloc(tsize); if (ret == NULL) return (NULL); - ret->binind = binind; - ret->nrounds = 0; +#ifdef MALLOC_STATS + memset(&ret->tstats, 0, sizeof(tcache_bin_stats_t)); +#endif + ret->low_water = 0; + ret->high_water = 0; + ret->ncached = 0; return (ret); } static void -mag_destroy(mag_t *mag) +tcache_bin_destroy(tcache_t *tcache, tcache_bin_t *tbin, unsigned binind) { arena_t *arena; arena_chunk_t *chunk; - size_t pageind; + size_t pageind, tsize; arena_chunk_map_t *mapelm; - chunk = CHUNK_ADDR2BASE(mag); + chunk = CHUNK_ADDR2BASE(tbin); arena = chunk->arena; - pageind = (((uintptr_t)mag - (uintptr_t)chunk) >> PAGE_SHIFT); + pageind = (((uintptr_t)tbin - (uintptr_t)chunk) >> PAGE_SHIFT); mapelm = &chunk->map[pageind]; - assert(mag->nrounds == 0); - if (sizeof(mag_t) + (sizeof(void *) * (max_rounds - 1)) <= - bin_maxclass) { +#ifdef MALLOC_STATS + if (tbin->tstats.nrequests != 0) { + arena_t *arena = tcache->arena; + arena_bin_t *bin = &arena->bins[binind]; + malloc_spin_lock(&arena->lock); + bin->stats.nrequests += tbin->tstats.nrequests; + if (bin->reg_size <= small_maxclass) + arena->stats.nmalloc_small += tbin->tstats.nrequests; + else + arena->stats.nmalloc_medium += tbin->tstats.nrequests; + malloc_spin_unlock(&arena->lock); + } +#endif + + assert(tbin->ncached == 0); + tsize = sizeof(tcache_bin_t) + (sizeof(void *) * (tcache_nslots - 1)); + if (tsize <= bin_maxclass) { malloc_spin_lock(&arena->lock); - arena_dalloc_small(arena, chunk, mag, mapelm); + arena_dalloc_bin(arena, chunk, tbin, mapelm); malloc_spin_unlock(&arena->lock); } else - idalloc(mag); + idalloc(tbin); +} + +#ifdef MALLOC_STATS +static void +tcache_stats_merge(tcache_t *tcache, arena_t *arena) +{ + unsigned i; + + /* Merge and reset tcache stats. */ + for (i = 0; i < mbin0; i++) { + arena_bin_t *bin = &arena->bins[i]; + tcache_bin_t *tbin = tcache->tbins[i]; + if (tbin != NULL) { + bin->stats.nrequests += tbin->tstats.nrequests; + arena->stats.nmalloc_small += tbin->tstats.nrequests; + tbin->tstats.nrequests = 0; + } + } + for (; i < nbins; i++) { + arena_bin_t *bin = &arena->bins[i]; + tcache_bin_t *tbin = tcache->tbins[i]; + if (tbin != NULL) { + bin->stats.nrequests += tbin->tstats.nrequests; + arena->stats.nmalloc_medium += tbin->tstats.nrequests; + tbin->tstats.nrequests = 0; + } + } } +#endif -static mag_rack_t * -mag_rack_create(arena_t *arena) +static tcache_t * +tcache_create(arena_t *arena) { + tcache_t *tcache; + + if (sizeof(tcache_t) + (sizeof(tcache_bin_t *) * (nbins - 1)) <= + small_maxclass) { + tcache = (tcache_t *)arena_malloc_small(arena, sizeof(tcache_t) + + (sizeof(tcache_bin_t *) * (nbins - 1)), true); + } else if (sizeof(tcache_t) + (sizeof(tcache_bin_t *) * (nbins - 1)) <= + bin_maxclass) { + tcache = (tcache_t *)arena_malloc_medium(arena, sizeof(tcache_t) + + (sizeof(tcache_bin_t *) * (nbins - 1)), true); + } else { + tcache = (tcache_t *)icalloc(sizeof(tcache_t) + + (sizeof(tcache_bin_t *) * (nbins - 1))); + } - assert(sizeof(mag_rack_t) + (sizeof(bin_mags_t *) * (nbins - 1)) <= - bin_maxclass); - return (arena_malloc_small(arena, sizeof(mag_rack_t) + - (sizeof(bin_mags_t) * (nbins - 1)), true)); + if (tcache == NULL) + return (NULL); + +#ifdef MALLOC_STATS + /* Link into list of extant tcaches. */ + malloc_spin_lock(&arena->lock); + ql_elm_new(tcache, link); + ql_tail_insert(&arena->tcache_ql, tcache, link); + malloc_spin_unlock(&arena->lock); +#endif + + tcache->arena = arena; + + tcache_tls = tcache; + + return (tcache); } static void -mag_rack_destroy(mag_rack_t *rack) +tcache_destroy(tcache_t *tcache) { - arena_t *arena; - arena_chunk_t *chunk; - bin_mags_t *bin_mags; - size_t i, pageind; - arena_chunk_map_t *mapelm; + unsigned i; + +#ifdef MALLOC_STATS + /* Unlink from list of extant tcaches. */ + malloc_spin_lock(&tcache->arena->lock); + ql_remove(&tcache->arena->tcache_ql, tcache, link); + tcache_stats_merge(tcache, tcache->arena); + malloc_spin_unlock(&tcache->arena->lock); +#endif for (i = 0; i < nbins; i++) { - bin_mags = &rack->bin_mags[i]; - if (bin_mags->curmag != NULL) { - assert(bin_mags->curmag->binind == i); - mag_unload(bin_mags->curmag); - mag_destroy(bin_mags->curmag); - } - if (bin_mags->sparemag != NULL) { - assert(bin_mags->sparemag->binind == i); - mag_unload(bin_mags->sparemag); - mag_destroy(bin_mags->sparemag); + tcache_bin_t *tbin = tcache->tbins[i]; + if (tbin != NULL) { + tcache_bin_flush(tbin, i, 0); + tcache_bin_destroy(tcache, tbin, i); } } - chunk = CHUNK_ADDR2BASE(rack); - arena = chunk->arena; - pageind = (((uintptr_t)rack - (uintptr_t)chunk) >> PAGE_SHIFT); - mapelm = &chunk->map[pageind]; + if (arena_salloc(tcache) <= bin_maxclass) { + arena_chunk_t *chunk = CHUNK_ADDR2BASE(tcache); + arena_t *arena = chunk->arena; + size_t pageind = (((uintptr_t)tcache - (uintptr_t)chunk) >> + PAGE_SHIFT); + arena_chunk_map_t *mapelm = &chunk->map[pageind]; - malloc_spin_lock(&arena->lock); - arena_dalloc_small(arena, chunk, rack, mapelm); - malloc_spin_unlock(&arena->lock); + malloc_spin_lock(&arena->lock); + arena_dalloc_bin(arena, chunk, tcache, mapelm); + malloc_spin_unlock(&arena->lock); + } else + idalloc(tcache); } #endif @@ -4249,7 +4903,7 @@ huge_malloc(size_t size, bool zero) if (node == NULL) return (NULL); - ret = chunk_alloc(csize, zero); + ret = chunk_alloc(csize, &zero); if (ret == NULL) { base_node_dealloc(node); return (NULL); @@ -4284,6 +4938,7 @@ huge_palloc(size_t alignment, size_t size) void *ret; size_t alloc_size, chunk_size, offset; extent_node_t *node; + bool zero; /* * This allocation requires alignment that is even larger than chunk @@ -4307,7 +4962,8 @@ huge_palloc(size_t alignment, size_t size) if (node == NULL) return (NULL); - ret = chunk_alloc(alloc_size, false); + zero = false; + ret = chunk_alloc(alloc_size, &zero); if (ret == NULL) { base_node_dealloc(node); return (NULL); @@ -4423,271 +5079,279 @@ huge_dalloc(void *ptr) } static void -malloc_print_stats(void) +malloc_stats_print(void) { + char s[UMAX2S_BUFSIZE]; - if (opt_print_stats) { - char s[UMAX2S_BUFSIZE]; - _malloc_message("___ Begin malloc statistics ___\n", "", "", - ""); - _malloc_message("Assertions ", + _malloc_message("___ Begin malloc statistics ___\n", "", "", ""); + _malloc_message("Assertions ", #ifdef NDEBUG - "disabled", + "disabled", #else - "enabled", + "enabled", #endif - "\n", ""); - _malloc_message("Boolean MALLOC_OPTIONS: ", - opt_abort ? "A" : "a", "", ""); + "\n", ""); + _malloc_message("Boolean MALLOC_OPTIONS: ", opt_abort ? "A" : "a", "", ""); #ifdef MALLOC_DSS - _malloc_message(opt_dss ? "D" : "d", "", "", ""); + _malloc_message(opt_dss ? "D" : "d", "", "", ""); #endif -#ifdef MALLOC_MAG - _malloc_message(opt_mag ? "G" : "g", "", "", ""); -#endif - _malloc_message(opt_junk ? "J" : "j", "", "", ""); + _malloc_message(opt_junk ? "J" : "j", "", "", ""); #ifdef MALLOC_DSS - _malloc_message(opt_mmap ? "M" : "m", "", "", ""); -#endif - _malloc_message(opt_utrace ? "PU" : "Pu", - opt_sysv ? "V" : "v", - opt_xmalloc ? "X" : "x", - opt_zero ? "Z\n" : "z\n"); - - _malloc_message("CPUs: ", umax2s(ncpus, s), "\n", ""); - _malloc_message("Max arenas: ", umax2s(narenas, s), "\n", ""); -#ifdef MALLOC_BALANCE - _malloc_message("Arena balance threshold: ", - umax2s(opt_balance_threshold, s), "\n", ""); -#endif - _malloc_message("Pointer size: ", umax2s(sizeof(void *), s), - "\n", ""); - _malloc_message("Quantum size: ", umax2s(QUANTUM, s), "\n", ""); - _malloc_message("Cacheline size (assumed): ", umax2s(CACHELINE, - s), "\n", ""); + _malloc_message(opt_mmap ? "M" : "m", "", "", ""); +#endif + _malloc_message("P", "", "", ""); + _malloc_message(opt_utrace ? "U" : "u", "", "", ""); + _malloc_message(opt_sysv ? "V" : "v", "", "", ""); + _malloc_message(opt_xmalloc ? "X" : "x", "", "", ""); + _malloc_message(opt_zero ? "Z" : "z", "", "", ""); + _malloc_message("\n", "", "", ""); + + _malloc_message("CPUs: ", umax2s(ncpus, 10, s), "\n", ""); + _malloc_message("Max arenas: ", umax2s(narenas, 10, s), "\n", ""); + _malloc_message("Pointer size: ", umax2s(sizeof(void *), 10, s), "\n", ""); + _malloc_message("Quantum size: ", umax2s(QUANTUM, 10, s), "\n", ""); + _malloc_message("Cacheline size (assumed): ", + umax2s(CACHELINE, 10, s), "\n", ""); + _malloc_message("Subpage spacing: ", umax2s(SUBPAGE, 10, s), "\n", ""); + _malloc_message("Medium spacing: ", umax2s((1U << lg_mspace), 10, s), "\n", + ""); #ifdef MALLOC_TINY - _malloc_message("Tiny 2^n-spaced sizes: [", umax2s((1U << - TINY_MIN_2POW), s), "..", ""); - _malloc_message(umax2s((qspace_min >> 1), s), "]\n", "", ""); -#endif - _malloc_message("Quantum-spaced sizes: [", umax2s(qspace_min, - s), "..", ""); - _malloc_message(umax2s(qspace_max, s), "]\n", "", ""); - _malloc_message("Cacheline-spaced sizes: [", umax2s(cspace_min, - s), "..", ""); - _malloc_message(umax2s(cspace_max, s), "]\n", "", ""); - _malloc_message("Subpage-spaced sizes: [", umax2s(sspace_min, - s), "..", ""); - _malloc_message(umax2s(sspace_max, s), "]\n", "", ""); -#ifdef MALLOC_MAG - _malloc_message("Rounds per magazine: ", umax2s(max_rounds, s), - "\n", ""); -#endif - _malloc_message("Max dirty pages per arena: ", - umax2s(opt_dirty_max, s), "\n", ""); - - _malloc_message("Chunk size: ", umax2s(chunksize, s), "", ""); - _malloc_message(" (2^", umax2s(opt_chunk_2pow, s), ")\n", ""); + _malloc_message("Tiny 2^n-spaced sizes: [", umax2s((1U << LG_TINY_MIN), 10, + s), "..", ""); + _malloc_message(umax2s((qspace_min >> 1), 10, s), "]\n", "", ""); +#endif + _malloc_message("Quantum-spaced sizes: [", umax2s(qspace_min, 10, s), "..", + ""); + _malloc_message(umax2s(qspace_max, 10, s), "]\n", "", ""); + _malloc_message("Cacheline-spaced sizes: [", + umax2s(cspace_min, 10, s), "..", ""); + _malloc_message(umax2s(cspace_max, 10, s), "]\n", "", ""); + _malloc_message("Subpage-spaced sizes: [", umax2s(sspace_min, 10, s), "..", + ""); + _malloc_message(umax2s(sspace_max, 10, s), "]\n", "", ""); + _malloc_message("Medium sizes: [", umax2s(medium_min, 10, s), "..", ""); + _malloc_message(umax2s(medium_max, 10, s), "]\n", "", ""); + if (opt_lg_dirty_mult >= 0) { + _malloc_message("Min active:dirty page ratio per arena: ", + umax2s((1U << opt_lg_dirty_mult), 10, s), ":1\n", ""); + } else { + _malloc_message("Min active:dirty page ratio per arena: N/A\n", "", + "", ""); + } +#ifdef MALLOC_TCACHE + _malloc_message("Thread cache slots per size class: ", + tcache_nslots ? umax2s(tcache_nslots, 10, s) : "N/A", "\n", ""); + _malloc_message("Thread cache GC sweep interval: ", + (tcache_nslots && tcache_gc_incr > 0) ? + umax2s((1U << opt_lg_tcache_gc_sweep), 10, s) : "N/A", "", ""); + _malloc_message(" (increment interval: ", + (tcache_nslots && tcache_gc_incr > 0) ? umax2s(tcache_gc_incr, 10, s) + : "N/A", ")\n", ""); +#endif + _malloc_message("Chunk size: ", umax2s(chunksize, 10, s), "", ""); + _malloc_message(" (2^", umax2s(opt_lg_chunk, 10, s), ")\n", ""); #ifdef MALLOC_STATS - { - size_t allocated, mapped; -#ifdef MALLOC_BALANCE - uint64_t nbalance = 0; -#endif - unsigned i; - arena_t *arena; - - /* Calculate and print allocated/mapped stats. */ - - /* arenas. */ - for (i = 0, allocated = 0; i < narenas; i++) { - if (arenas[i] != NULL) { - malloc_spin_lock(&arenas[i]->lock); - allocated += - arenas[i]->stats.allocated_small; - allocated += - arenas[i]->stats.allocated_large; -#ifdef MALLOC_BALANCE - nbalance += arenas[i]->stats.nbalance; -#endif - malloc_spin_unlock(&arenas[i]->lock); - } + { + size_t allocated, mapped; + unsigned i; + arena_t *arena; + + /* Calculate and print allocated/mapped stats. */ + + /* arenas. */ + for (i = 0, allocated = 0; i < narenas; i++) { + if (arenas[i] != NULL) { + malloc_spin_lock(&arenas[i]->lock); + allocated += arenas[i]->stats.allocated_small; + allocated += arenas[i]->stats.allocated_large; + malloc_spin_unlock(&arenas[i]->lock); } + } - /* huge/base. */ - malloc_mutex_lock(&huge_mtx); - allocated += huge_allocated; - mapped = stats_chunks.curchunks * chunksize; - malloc_mutex_unlock(&huge_mtx); + /* huge/base. */ + malloc_mutex_lock(&huge_mtx); + allocated += huge_allocated; + mapped = stats_chunks.curchunks * chunksize; + malloc_mutex_unlock(&huge_mtx); - malloc_mutex_lock(&base_mtx); - mapped += base_mapped; - malloc_mutex_unlock(&base_mtx); + malloc_mutex_lock(&base_mtx); + mapped += base_mapped; + malloc_mutex_unlock(&base_mtx); - malloc_printf("Allocated: %zu, mapped: %zu\n", - allocated, mapped); + malloc_printf("Allocated: %zu, mapped: %zu\n", allocated, + mapped); -#ifdef MALLOC_BALANCE - malloc_printf("Arena balance reassignments: %llu\n", - nbalance); -#endif + /* Print chunk stats. */ + { + chunk_stats_t chunks_stats; - /* Print chunk stats. */ - { - chunk_stats_t chunks_stats; + malloc_mutex_lock(&huge_mtx); + chunks_stats = stats_chunks; + malloc_mutex_unlock(&huge_mtx); - malloc_mutex_lock(&huge_mtx); - chunks_stats = stats_chunks; - malloc_mutex_unlock(&huge_mtx); + malloc_printf("chunks: nchunks " + "highchunks curchunks\n"); + malloc_printf(" %13"PRIu64"%13zu%13zu\n", + chunks_stats.nchunks, chunks_stats.highchunks, + chunks_stats.curchunks); + } - malloc_printf("chunks: nchunks " - "highchunks curchunks\n"); - malloc_printf(" %13llu%13lu%13lu\n", - chunks_stats.nchunks, - chunks_stats.highchunks, - chunks_stats.curchunks); - } + /* Print chunk stats. */ + malloc_printf( + "huge: nmalloc ndalloc allocated\n"); + malloc_printf(" %12"PRIu64" %12"PRIu64" %12zu\n", huge_nmalloc, + huge_ndalloc, huge_allocated); - /* Print chunk stats. */ - malloc_printf( - "huge: nmalloc ndalloc allocated\n"); - malloc_printf(" %12llu %12llu %12zu\n", - huge_nmalloc, huge_ndalloc, huge_allocated); - - /* Print stats for each arena. */ - for (i = 0; i < narenas; i++) { - arena = arenas[i]; - if (arena != NULL) { - malloc_printf( - "\narenas[%u]:\n", i); - malloc_spin_lock(&arena->lock); - stats_print(arena); - malloc_spin_unlock(&arena->lock); - } + /* Print stats for each arena. */ + for (i = 0; i < narenas; i++) { + arena = arenas[i]; + if (arena != NULL) { + malloc_printf("\narenas[%u]:\n", i); + malloc_spin_lock(&arena->lock); + arena_stats_print(arena); + malloc_spin_unlock(&arena->lock); } } -#endif /* #ifdef MALLOC_STATS */ - _malloc_message("--- End malloc statistics ---\n", "", "", ""); } +#endif /* #ifdef MALLOC_STATS */ + _malloc_message("--- End malloc statistics ---\n", "", "", ""); } #ifdef MALLOC_DEBUG static void -size2bin_validate(void) +small_size2bin_validate(void) { size_t i, size, binind; - assert(size2bin[0] == 0xffU); + assert(small_size2bin[0] == 0xffU); i = 1; # ifdef MALLOC_TINY /* Tiny. */ - for (; i < (1U << TINY_MIN_2POW); i++) { - size = pow2_ceil(1U << TINY_MIN_2POW); - binind = ffs((int)(size >> (TINY_MIN_2POW + 1))); - assert(size2bin[i] == binind); + for (; i < (1U << LG_TINY_MIN); i++) { + size = pow2_ceil(1U << LG_TINY_MIN); + binind = ffs((int)(size >> (LG_TINY_MIN + 1))); + assert(small_size2bin[i] == binind); } for (; i < qspace_min; i++) { size = pow2_ceil(i); - binind = ffs((int)(size >> (TINY_MIN_2POW + 1))); - assert(size2bin[i] == binind); + binind = ffs((int)(size >> (LG_TINY_MIN + 1))); + assert(small_size2bin[i] == binind); } # endif /* Quantum-spaced. */ for (; i <= qspace_max; i++) { size = QUANTUM_CEILING(i); - binind = ntbins + (size >> QUANTUM_2POW) - 1; - assert(size2bin[i] == binind); + binind = ntbins + (size >> LG_QUANTUM) - 1; + assert(small_size2bin[i] == binind); } /* Cacheline-spaced. */ for (; i <= cspace_max; i++) { size = CACHELINE_CEILING(i); binind = ntbins + nqbins + ((size - cspace_min) >> - CACHELINE_2POW); - assert(size2bin[i] == binind); + LG_CACHELINE); + assert(small_size2bin[i] == binind); } /* Sub-page. */ for (; i <= sspace_max; i++) { size = SUBPAGE_CEILING(i); binind = ntbins + nqbins + ncbins + ((size - sspace_min) - >> SUBPAGE_2POW); - assert(size2bin[i] == binind); + >> LG_SUBPAGE); + assert(small_size2bin[i] == binind); } } #endif static bool -size2bin_init(void) +small_size2bin_init(void) { - if (opt_qspace_max_2pow != QSPACE_MAX_2POW_DEFAULT - || opt_cspace_max_2pow != CSPACE_MAX_2POW_DEFAULT) - return (size2bin_init_hard()); + if (opt_lg_qspace_max != LG_QSPACE_MAX_DEFAULT + || opt_lg_cspace_max != LG_CSPACE_MAX_DEFAULT + || sizeof(const_small_size2bin) != small_maxclass + 1) + return (small_size2bin_init_hard()); - size2bin = const_size2bin; + small_size2bin = const_small_size2bin; #ifdef MALLOC_DEBUG - assert(sizeof(const_size2bin) == bin_maxclass + 1); - size2bin_validate(); + assert(sizeof(const_small_size2bin) == small_maxclass + 1); + small_size2bin_validate(); #endif return (false); } static bool -size2bin_init_hard(void) +small_size2bin_init_hard(void) { size_t i, size, binind; - uint8_t *custom_size2bin; + uint8_t *custom_small_size2bin; - assert(opt_qspace_max_2pow != QSPACE_MAX_2POW_DEFAULT - || opt_cspace_max_2pow != CSPACE_MAX_2POW_DEFAULT); + assert(opt_lg_qspace_max != LG_QSPACE_MAX_DEFAULT + || opt_lg_cspace_max != LG_CSPACE_MAX_DEFAULT + || sizeof(const_small_size2bin) != small_maxclass + 1); - custom_size2bin = (uint8_t *)base_alloc(bin_maxclass + 1); - if (custom_size2bin == NULL) + custom_small_size2bin = (uint8_t *)base_alloc(small_maxclass + 1); + if (custom_small_size2bin == NULL) return (true); - custom_size2bin[0] = 0xffU; + custom_small_size2bin[0] = 0xffU; i = 1; #ifdef MALLOC_TINY /* Tiny. */ - for (; i < (1U << TINY_MIN_2POW); i++) { - size = pow2_ceil(1U << TINY_MIN_2POW); - binind = ffs((int)(size >> (TINY_MIN_2POW + 1))); - custom_size2bin[i] = binind; + for (; i < (1U << LG_TINY_MIN); i++) { + size = pow2_ceil(1U << LG_TINY_MIN); + binind = ffs((int)(size >> (LG_TINY_MIN + 1))); + custom_small_size2bin[i] = binind; } for (; i < qspace_min; i++) { size = pow2_ceil(i); - binind = ffs((int)(size >> (TINY_MIN_2POW + 1))); - custom_size2bin[i] = binind; + binind = ffs((int)(size >> (LG_TINY_MIN + 1))); + custom_small_size2bin[i] = binind; } #endif /* Quantum-spaced. */ for (; i <= qspace_max; i++) { size = QUANTUM_CEILING(i); - binind = ntbins + (size >> QUANTUM_2POW) - 1; - custom_size2bin[i] = binind; + binind = ntbins + (size >> LG_QUANTUM) - 1; + custom_small_size2bin[i] = binind; } /* Cacheline-spaced. */ for (; i <= cspace_max; i++) { size = CACHELINE_CEILING(i); binind = ntbins + nqbins + ((size - cspace_min) >> - CACHELINE_2POW); - custom_size2bin[i] = binind; + LG_CACHELINE); + custom_small_size2bin[i] = binind; } /* Sub-page. */ for (; i <= sspace_max; i++) { size = SUBPAGE_CEILING(i); binind = ntbins + nqbins + ncbins + ((size - sspace_min) >> - SUBPAGE_2POW); - custom_size2bin[i] = binind; + LG_SUBPAGE); + custom_small_size2bin[i] = binind; } - size2bin = custom_size2bin; + small_size2bin = custom_small_size2bin; #ifdef MALLOC_DEBUG - size2bin_validate(); + small_size2bin_validate(); #endif return (false); } +static unsigned +malloc_ncpus(void) +{ + unsigned ret; + size_t retlen = sizeof(ret); + int mib[] = {CTL_HW, HW_NCPU}; + + if (sysctl(mib, sizeof(mib) / sizeof(int), &ret, &retlen, + (void *)0, 0) == -1) { + /* Error. */ + ret = 1; + } + + return (ret); +} + /* * FreeBSD's pthreads implementation calls malloc(3), so the malloc * implementation has to take pains to avoid infinite recursion during @@ -4722,18 +5386,7 @@ malloc_init_hard(void) } /* Get number of CPUs. */ - { - int mib[2]; - size_t len; - - mib[0] = CTL_HW; - mib[1] = HW_NCPU; - len = sizeof(ncpus); - if (sysctl(mib, 2, &ncpus, &len, (void *) 0, 0) == -1) { - /* Error. */ - ncpus = 1; - } - } + ncpus = malloc_ncpus(); /* * Increase the chunk size to the largest page size that is greater @@ -4746,8 +5399,8 @@ malloc_init_hard(void) nsizes = getpagesizes(pagesizes, MAXPAGESIZES); for (k = 0; k < nsizes; k++) if (pagesizes[k] <= (1LU << 22)) - while ((1LU << opt_chunk_2pow) < pagesizes[k]) - opt_chunk_2pow++; + while ((1LU << opt_lg_chunk) < pagesizes[k]) + opt_lg_chunk++; } for (i = 0; i < 3; i++) { @@ -4800,6 +5453,8 @@ malloc_init_hard(void) default: /* NOTREACHED */ assert(false); + buf[0] = '\0'; + opts = buf; } for (j = 0; opts[j] != '\0'; j++) { @@ -4831,31 +5486,17 @@ MALLOC_OUT: case 'A': opt_abort = true; break; - case 'b': -#ifdef MALLOC_BALANCE - opt_balance_threshold >>= 1; -#endif - break; - case 'B': -#ifdef MALLOC_BALANCE - if (opt_balance_threshold == 0) - opt_balance_threshold = 1; - else if ((opt_balance_threshold << 1) - > opt_balance_threshold) - opt_balance_threshold <<= 1; -#endif - break; case 'c': - if (opt_cspace_max_2pow - 1 > - opt_qspace_max_2pow && - opt_cspace_max_2pow > - CACHELINE_2POW) - opt_cspace_max_2pow--; + if (opt_lg_cspace_max - 1 > + opt_lg_qspace_max && + opt_lg_cspace_max > + LG_CACHELINE) + opt_lg_cspace_max--; break; case 'C': - if (opt_cspace_max_2pow < PAGE_SHIFT + if (opt_lg_cspace_max < PAGE_SHIFT - 1) - opt_cspace_max_2pow++; + opt_lg_cspace_max++; break; case 'd': #ifdef MALLOC_DSS @@ -4867,21 +5508,42 @@ MALLOC_OUT: opt_dss = true; #endif break; + case 'e': + if (opt_lg_medium_max > PAGE_SHIFT) + opt_lg_medium_max--; + break; + case 'E': + if (opt_lg_medium_max + 1 < + opt_lg_chunk) + opt_lg_medium_max++; + break; case 'f': - opt_dirty_max >>= 1; + if (opt_lg_dirty_mult + 1 < + (sizeof(size_t) << 3)) + opt_lg_dirty_mult++; break; case 'F': - if (opt_dirty_max == 0) - opt_dirty_max = 1; - else if ((opt_dirty_max << 1) != 0) - opt_dirty_max <<= 1; + if (opt_lg_dirty_mult >= 0) + opt_lg_dirty_mult--; break; -#ifdef MALLOC_MAG +#ifdef MALLOC_TCACHE case 'g': - opt_mag = false; + if (opt_lg_tcache_gc_sweep >= 0) + opt_lg_tcache_gc_sweep--; break; case 'G': - opt_mag = true; + if (opt_lg_tcache_gc_sweep + 1 < + (sizeof(size_t) << 3)) + opt_lg_tcache_gc_sweep++; + break; + case 'h': + if (opt_lg_tcache_nslots > 0) + opt_lg_tcache_nslots--; + break; + case 'H': + if (opt_lg_tcache_nslots + 1 < + (sizeof(size_t) << 3)) + opt_lg_tcache_nslots++; break; #endif case 'j': @@ -4893,16 +5555,20 @@ MALLOC_OUT: case 'k': /* * Chunks always require at least one - * header page, so chunks can never be - * smaller than two pages. + * header page, plus enough room to + * hold a run for the largest medium + * size class (one page more than the + * size). */ - if (opt_chunk_2pow > PAGE_SHIFT + 1) - opt_chunk_2pow--; + if ((1U << (opt_lg_chunk - 1)) >= + (2U << PAGE_SHIFT) + (1U << + opt_lg_medium_max)) + opt_lg_chunk--; break; case 'K': - if (opt_chunk_2pow + 1 < + if (opt_lg_chunk + 1 < (sizeof(size_t) << 3)) - opt_chunk_2pow++; + opt_lg_chunk++; break; case 'm': #ifdef MALLOC_DSS @@ -4921,36 +5587,20 @@ MALLOC_OUT: opt_narenas_lshift++; break; case 'p': - opt_print_stats = false; + opt_stats_print = false; break; case 'P': - opt_print_stats = true; + opt_stats_print = true; break; case 'q': - if (opt_qspace_max_2pow > QUANTUM_2POW) - opt_qspace_max_2pow--; + if (opt_lg_qspace_max > LG_QUANTUM) + opt_lg_qspace_max--; break; case 'Q': - if (opt_qspace_max_2pow + 1 < - opt_cspace_max_2pow) - opt_qspace_max_2pow++; - break; -#ifdef MALLOC_MAG - case 'R': - if (opt_mag_size_2pow + 1 < (8U << - SIZEOF_PTR_2POW)) - opt_mag_size_2pow++; - break; - case 'r': - /* - * Make sure there's always at least - * one round per magazine. - */ - if ((1U << (opt_mag_size_2pow-1)) >= - sizeof(mag_t)) - opt_mag_size_2pow--; + if (opt_lg_qspace_max + 1 < + opt_lg_cspace_max) + opt_lg_qspace_max++; break; -#endif case 'u': opt_utrace = false; break; @@ -4995,50 +5645,87 @@ MALLOC_OUT: if (opt_dss == false && opt_mmap == false) opt_mmap = true; #endif - - /* Take care to call atexit() only once. */ - if (opt_print_stats) { + if (opt_stats_print) { /* Print statistics at exit. */ - atexit(malloc_print_stats); + atexit(stats_print_atexit); } -#ifdef MALLOC_MAG - /* - * Calculate the actual number of rounds per magazine, taking into - * account header overhead. - */ - max_rounds = (1LLU << (opt_mag_size_2pow - SIZEOF_PTR_2POW)) - - (sizeof(mag_t) >> SIZEOF_PTR_2POW) + 1; -#endif - /* Set variables according to the value of opt_[qc]space_max_2pow. */ - qspace_max = (1U << opt_qspace_max_2pow); + /* Set variables according to the value of opt_lg_[qc]space_max. */ + qspace_max = (1U << opt_lg_qspace_max); cspace_min = CACHELINE_CEILING(qspace_max); if (cspace_min == qspace_max) cspace_min += CACHELINE; - cspace_max = (1U << opt_cspace_max_2pow); + cspace_max = (1U << opt_lg_cspace_max); sspace_min = SUBPAGE_CEILING(cspace_max); if (sspace_min == cspace_max) sspace_min += SUBPAGE; assert(sspace_min < PAGE_SIZE); sspace_max = PAGE_SIZE - SUBPAGE; + medium_max = (1U << opt_lg_medium_max); #ifdef MALLOC_TINY - assert(QUANTUM_2POW >= TINY_MIN_2POW); + assert(LG_QUANTUM >= LG_TINY_MIN); #endif - assert(ntbins <= QUANTUM_2POW); - nqbins = qspace_max >> QUANTUM_2POW; - ncbins = ((cspace_max - cspace_min) >> CACHELINE_2POW) + 1; - nsbins = ((sspace_max - sspace_min) >> SUBPAGE_2POW) + 1; - nbins = ntbins + nqbins + ncbins + nsbins; + assert(ntbins <= LG_QUANTUM); + nqbins = qspace_max >> LG_QUANTUM; + ncbins = ((cspace_max - cspace_min) >> LG_CACHELINE) + 1; + nsbins = ((sspace_max - sspace_min) >> LG_SUBPAGE) + 1; + + /* + * Compute medium size class spacing and the number of medium size + * classes. Limit spacing to no more than pagesize, but if possible + * use the smallest spacing that does not exceed NMBINS_MAX medium size + * classes. + */ + lg_mspace = LG_SUBPAGE; + nmbins = ((medium_max - medium_min) >> lg_mspace) + 1; + while (lg_mspace < PAGE_SHIFT && nmbins > NMBINS_MAX) { + lg_mspace = lg_mspace + 1; + nmbins = ((medium_max - medium_min) >> lg_mspace) + 1; + } + mspace_mask = (1U << lg_mspace) - 1U; + + mbin0 = ntbins + nqbins + ncbins + nsbins; + nbins = mbin0 + nmbins; + /* + * The small_size2bin lookup table uses uint8_t to encode each bin + * index, so we cannot support more than 256 small size classes. This + * limit is difficult to exceed (not even possible with 16B quantum and + * 4KiB pages), and such configurations are impractical, but + * nonetheless we need to protect against this case in order to avoid + * undefined behavior. + */ + if (mbin0 > 256) { + char line_buf[UMAX2S_BUFSIZE]; + _malloc_message(_getprogname(), + ": (malloc) Too many small size classes (", + umax2s(mbin0, 10, line_buf), " > max 256)\n"); + abort(); + } - if (size2bin_init()) { + if (small_size2bin_init()) { malloc_mutex_unlock(&init_lock); return (true); } - /* Set variables according to the value of opt_chunk_2pow. */ - chunksize = (1LU << opt_chunk_2pow); +#ifdef MALLOC_TCACHE + if (opt_lg_tcache_nslots > 0) { + tcache_nslots = (1U << opt_lg_tcache_nslots); + + /* Compute incremental GC event threshold. */ + if (opt_lg_tcache_gc_sweep >= 0) { + tcache_gc_incr = ((1U << opt_lg_tcache_gc_sweep) / + nbins) + (((1U << opt_lg_tcache_gc_sweep) % nbins == + 0) ? 0 : 1); + } else + tcache_gc_incr = 0; + } else + tcache_nslots = 0; +#endif + + /* Set variables according to the value of opt_lg_chunk. */ + chunksize = (1LU << opt_lg_chunk); chunksize_mask = chunksize - 1; chunk_npages = (chunksize >> PAGE_SHIFT); { @@ -5059,6 +5746,7 @@ MALLOC_OUT: UTRACE((void *)(intptr_t)(-1), 0, 0); #ifdef MALLOC_STATS + malloc_mutex_init(&chunks_mtx); memset(&stats_chunks, 0, sizeof(chunk_stats_t)); #endif @@ -5100,10 +5788,27 @@ MALLOC_OUT: if (ncpus > 1) { /* - * For SMP systems, create twice as many arenas as there are - * CPUs by default. + * For SMP systems, create more than one arena per CPU by + * default. */ - opt_narenas_lshift++; +#ifdef MALLOC_TCACHE + if (tcache_nslots) { + /* + * Only large object allocation/deallocation is + * guaranteed to acquire an arena mutex, so we can get + * away with fewer arenas than without thread caching. + */ + opt_narenas_lshift += 1; + } else { +#endif + /* + * All allocations must acquire an arena mutex, so use + * plenty of arenas. + */ + opt_narenas_lshift += 2; +#ifdef MALLOC_TCACHE + } +#endif } /* Determine how many arenas to use. */ @@ -5124,12 +5829,6 @@ MALLOC_OUT: if (narenas == 0) narenas = 1; } -#ifdef MALLOC_BALANCE - assert(narenas != 0); - for (narenas_2pow = 0; - (narenas >> (narenas_2pow + 1)) != 0; - narenas_2pow++); -#endif #ifdef NO_TLS if (narenas > 1) { @@ -5146,7 +5845,7 @@ MALLOC_OUT: * spread allocations evenly among the arenas. */ assert((narenas & 1) == 0); /* narenas must be even. */ - nprimes = (sizeof(primes) >> SIZEOF_INT_2POW); + nprimes = (sizeof(primes) >> LG_SIZEOF_INT); parenas = primes[nprimes - 1]; /* In case not enough primes. */ for (i = 1; i < nprimes; i++) { if (primes[i] > narenas) { @@ -5159,9 +5858,7 @@ MALLOC_OUT: #endif #ifndef NO_TLS -# ifndef MALLOC_BALANCE next_arena = 0; -# endif #endif /* Allocate and initialize arenas. */ @@ -5193,14 +5890,6 @@ MALLOC_OUT: */ arenas_map = arenas[0]; #endif - /* - * Seed here for the initial thread, since choose_arena_hard() is only - * called for other threads. The seed value doesn't really matter. - */ -#ifdef MALLOC_BALANCE - SPRN(balance, 42); -#endif - malloc_spin_init(&arenas_lock); malloc_initialized = true; @@ -5223,13 +5912,19 @@ malloc(size_t size) if (malloc_init()) { ret = NULL; - goto RETURN; + goto OOM; } if (size == 0) { if (opt_sysv == false) size = 1; else { + if (opt_xmalloc) { + _malloc_message(_getprogname(), + ": (malloc) Error in malloc(): " + "invalid size 0\n", "", ""); + abort(); + } ret = NULL; goto RETURN; } @@ -5237,7 +5932,7 @@ malloc(size_t size) ret = imalloc(size); -RETURN: +OOM: if (ret == NULL) { if (opt_xmalloc) { _malloc_message(_getprogname(), @@ -5248,6 +5943,7 @@ RETURN: errno = ENOMEM; } +RETURN: UTRACE(0, size, ret); return (ret); } @@ -5261,6 +5957,24 @@ posix_memalign(void **memptr, size_t alignment, size_t size) if (malloc_init()) result = NULL; else { + if (size == 0) { + if (opt_sysv == false) + size = 1; + else { + if (opt_xmalloc) { + _malloc_message(_getprogname(), + ": (malloc) Error in " + "posix_memalign(): invalid " + "size 0\n", "", ""); + abort(); + } + result = NULL; + *memptr = NULL; + ret = 0; + goto RETURN; + } + } + /* Make sure that alignment is a large enough power of 2. */ if (((alignment - 1) & alignment) != 0 || alignment < sizeof(void *)) { @@ -5275,16 +5989,6 @@ posix_memalign(void **memptr, size_t alignment, size_t size) goto RETURN; } - if (size == 0) { - if (opt_sysv == false) - size = 1; - else { - result = NULL; - *memptr = NULL; - ret = 0; - goto RETURN; - } - } result = ipalloc(alignment, size); } @@ -5445,11 +6149,6 @@ malloc_usable_size(const void *ptr) * Begin library-private functions. */ -/******************************************************************************/ -/* - * Begin thread cache. - */ - /* * We provide an unpublished interface in order to receive notifications from * the pthreads library whenever a thread exits. This allows us to clean up @@ -5459,13 +6158,13 @@ void _malloc_thread_cleanup(void) { -#ifdef MALLOC_MAG - if (mag_rack != NULL) { - assert(mag_rack != (void *)-1); - mag_rack_destroy(mag_rack); -#ifdef MALLOC_DEBUG - mag_rack = (void *)-1; -#endif +#ifdef MALLOC_TCACHE + tcache_t *tcache = tcache_tls; + + if (tcache != NULL) { + assert(tcache != (void *)(uintptr_t)1); + tcache_destroy(tcache); + tcache_tls = (void *)(uintptr_t)1; } #endif } @@ -5480,41 +6179,14 @@ _malloc_thread_cleanup(void) void _malloc_prefork(void) { - bool again; - unsigned i, j; - arena_t *larenas[narenas], *tarenas[narenas]; + unsigned i; /* Acquire all mutexes in a safe order. */ - - /* - * arenas_lock must be acquired after all of the arena mutexes, in - * order to avoid potential deadlock with arena_lock_balance[_hard](). - * Since arenas_lock protects the arenas array, the following code has - * to race with arenas_extend() callers until it succeeds in locking - * all arenas before locking arenas_lock. - */ - memset(larenas, 0, sizeof(arena_t *) * narenas); - do { - again = false; - - malloc_spin_lock(&arenas_lock); - for (i = 0; i < narenas; i++) { - if (arenas[i] != larenas[i]) { - memcpy(tarenas, arenas, sizeof(arena_t *) * - narenas); - malloc_spin_unlock(&arenas_lock); - for (j = 0; j < narenas; j++) { - if (larenas[j] != tarenas[j]) { - larenas[j] = tarenas[j]; - malloc_spin_lock( - &larenas[j]->lock); - } - } - again = true; - break; - } - } - } while (again); + malloc_spin_lock(&arenas_lock); + for (i = 0; i < narenas; i++) { + if (arenas[i] != NULL) + malloc_spin_lock(&arenas[i]->lock); + } malloc_mutex_lock(&base_mtx); @@ -5529,7 +6201,6 @@ void _malloc_postfork(void) { unsigned i; - arena_t *larenas[narenas]; /* Release all mutexes, now that fork() has completed. */ @@ -5541,12 +6212,11 @@ _malloc_postfork(void) malloc_mutex_unlock(&base_mtx); - memcpy(larenas, arenas, sizeof(arena_t *) * narenas); - malloc_spin_unlock(&arenas_lock); for (i = 0; i < narenas; i++) { - if (larenas[i] != NULL) - malloc_spin_unlock(&larenas[i]->lock); + if (arenas[i] != NULL) + malloc_spin_unlock(&arenas[i]->lock); } + malloc_spin_unlock(&arenas_lock); } /* diff --git a/lib/libc/stdlib/ql.h b/lib/libc/stdlib/ql.h new file mode 100644 index 0000000..a1bc3ab --- /dev/null +++ b/lib/libc/stdlib/ql.h @@ -0,0 +1,122 @@ +/****************************************************************************** + * + * Copyright (C) 2002 Jason Evans . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice(s), this list of conditions and the following disclaimer + * unmodified other than the allowable addition of one or more + * copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ******************************************************************************/ + +#ifndef QL_H_ +#define QL_H_ + +#include +__FBSDID("$FreeBSD$"); + +/* + * List definitions. + */ +#define ql_head(a_type) \ +struct { \ + a_type *qlh_first; \ +} + +#define ql_head_initializer(a_head) {NULL} + +#define ql_elm(a_type) qr(a_type) + +/* List functions. */ +#define ql_new(a_head) do { \ + (a_head)->qlh_first = NULL; \ +} while (0) + +#define ql_elm_new(a_elm, a_field) qr_new((a_elm), a_field) + +#define ql_first(a_head) ((a_head)->qlh_first) + +#define ql_last(a_head, a_field) \ + ((ql_first(a_head) != NULL) \ + ? qr_prev(ql_first(a_head), a_field) : NULL) + +#define ql_next(a_head, a_elm, a_field) \ + ((ql_last(a_head, a_field) != (a_elm)) \ + ? qr_next((a_elm), a_field) : NULL) + +#define ql_prev(a_head, a_elm, a_field) \ + ((ql_first(a_head) != (a_elm)) ? qr_prev((a_elm), a_field) \ + : NULL) + +#define ql_before_insert(a_head, a_qlelm, a_elm, a_field) do { \ + qr_before_insert((a_qlelm), (a_elm), a_field); \ + if (ql_first(a_head) == (a_qlelm)) { \ + ql_first(a_head) = (a_elm); \ + } \ +} while (0) + +#define ql_after_insert(a_qlelm, a_elm, a_field) \ + qr_after_insert((a_qlelm), (a_elm), a_field) + +#define ql_head_insert(a_head, a_elm, a_field) do { \ + if (ql_first(a_head) != NULL) { \ + qr_before_insert(ql_first(a_head), (a_elm), a_field); \ + } \ + ql_first(a_head) = (a_elm); \ +} while (0) + +#define ql_tail_insert(a_head, a_elm, a_field) do { \ + if (ql_first(a_head) != NULL) { \ + qr_before_insert(ql_first(a_head), (a_elm), a_field); \ + } \ + ql_first(a_head) = qr_next((a_elm), a_field); \ +} while (0) + +#define ql_remove(a_head, a_elm, a_field) do { \ + if (ql_first(a_head) == (a_elm)) { \ + ql_first(a_head) = qr_next(ql_first(a_head), a_field); \ + } \ + if (ql_first(a_head) != (a_elm)) { \ + qr_remove((a_elm), a_field); \ + } else { \ + ql_first(a_head) = NULL; \ + } \ +} while (0) + +#define ql_head_remove(a_head, a_type, a_field) do { \ + a_type *t = ql_first(a_head); \ + ql_remove((a_head), t, a_field); \ +} while (0) + +#define ql_tail_remove(a_head, a_type, a_field) do { \ + a_type *t = ql_last(a_head, a_field); \ + ql_remove((a_head), t, a_field); \ +} while (0) + +#define ql_foreach(a_var, a_head, a_field) \ + qr_foreach((a_var), ql_first(a_head), a_field) + +#define ql_reverse_foreach(a_var, a_head, a_field) \ + qr_reverse_foreach((a_var), ql_first(a_head), a_field) + +#endif /* QL_H_ */ diff --git a/lib/libc/stdlib/qr.h b/lib/libc/stdlib/qr.h new file mode 100644 index 0000000..6e02321 --- /dev/null +++ b/lib/libc/stdlib/qr.h @@ -0,0 +1,106 @@ +/****************************************************************************** + * + * Copyright (C) 2002 Jason Evans . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice(s), this list of conditions and the following disclaimer + * unmodified other than the allowable addition of one or more + * copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ******************************************************************************/ + +#ifndef QR_H_ +#define QR_H_ + +#include +__FBSDID("$FreeBSD$"); + +/* Ring definitions. */ +#define qr(a_type) \ +struct { \ + a_type *qre_next; \ + a_type *qre_prev; \ +} + +/* Ring functions. */ +#define qr_new(a_qr, a_field) do { \ + (a_qr)->a_field.qre_next = (a_qr); \ + (a_qr)->a_field.qre_prev = (a_qr); \ +} while (0) + +#define qr_next(a_qr, a_field) ((a_qr)->a_field.qre_next) + +#define qr_prev(a_qr, a_field) ((a_qr)->a_field.qre_prev) + +#define qr_before_insert(a_qrelm, a_qr, a_field) do { \ + (a_qr)->a_field.qre_prev = (a_qrelm)->a_field.qre_prev; \ + (a_qr)->a_field.qre_next = (a_qrelm); \ + (a_qr)->a_field.qre_prev->a_field.qre_next = (a_qr); \ + (a_qrelm)->a_field.qre_prev = (a_qr); \ +} while (0) + +#define qr_after_insert(a_qrelm, a_qr, a_field) \ + do \ + { \ + (a_qr)->a_field.qre_next = (a_qrelm)->a_field.qre_next; \ + (a_qr)->a_field.qre_prev = (a_qrelm); \ + (a_qr)->a_field.qre_next->a_field.qre_prev = (a_qr); \ + (a_qrelm)->a_field.qre_next = (a_qr); \ + } while (0) + +#define qr_meld(a_qr_a, a_qr_b, a_field) do { \ + void *t; \ + (a_qr_a)->a_field.qre_prev->a_field.qre_next = (a_qr_b); \ + (a_qr_b)->a_field.qre_prev->a_field.qre_next = (a_qr_a); \ + t = (a_qr_a)->a_field.qre_prev; \ + (a_qr_a)->a_field.qre_prev = (a_qr_b)->a_field.qre_prev; \ + (a_qr_b)->a_field.qre_prev = t; \ +} while (0) + +/* qr_meld() and qr_split() are functionally equivalent, so there's no need to + * have two copies of the code. */ +#define qr_split(a_qr_a, a_qr_b, a_field) \ + qr_meld((a_qr_a), (a_qr_b), a_field) + +#define qr_remove(a_qr, a_field) do { \ + (a_qr)->a_field.qre_prev->a_field.qre_next \ + = (a_qr)->a_field.qre_next; \ + (a_qr)->a_field.qre_next->a_field.qre_prev \ + = (a_qr)->a_field.qre_prev; \ + (a_qr)->a_field.qre_next = (a_qr); \ + (a_qr)->a_field.qre_prev = (a_qr); \ +} while (0) + +#define qr_foreach(var, a_qr, a_field) \ + for ((var) = (a_qr); \ + (var) != NULL; \ + (var) = (((var)->a_field.qre_next != (a_qr)) \ + ? (var)->a_field.qre_next : NULL)) + +#define qr_reverse_foreach(var, a_qr, a_field) \ + for ((var) = ((a_qr) != NULL) ? qr_prev(a_qr, a_field) : NULL; \ + (var) != NULL; \ + (var) = (((var) != (a_qr)) \ + ? (var)->a_field.qre_prev : NULL)) + +#endif /* QR_H_ */ -- cgit v1.1 From ca42e1d1ceb9cfd3924a389a273d173d25ae7523 Mon Sep 17 00:00:00 2001 From: ed Date: Tue, 2 Feb 2010 19:02:08 +0000 Subject: Implement strndup(3) using strnlen(3). This makes the implementation a bit more consistent with strdup(3), which uses strlen(3). --- lib/libc/string/strndup.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/string/strndup.c b/lib/libc/string/strndup.c index 56aa6a8..abb1e03 100644 --- a/lib/libc/string/strndup.c +++ b/lib/libc/string/strndup.c @@ -42,9 +42,7 @@ strndup(const char *str, size_t n) size_t len; char *copy; - for (len = 0; len < n && str[len]; len++) - continue; - + len = strnlen(str, n); if ((copy = malloc(len + 1)) == NULL) return (NULL); memcpy(copy, str, len); -- cgit v1.1 From f4a1ca000f01cb18d4e8ebe16dddcf0745b7a03b Mon Sep 17 00:00:00 2001 From: gavin Date: Tue, 2 Feb 2010 19:28:01 +0000 Subject: The multiplicand a = 0x5deece66d = 25214903917, not 0xfdeece66d. This bug in the man page has gone unnoticed for over 15 years! PR: docs/143461 Submitted by: Jeremy Huddleston jeremyhu apple.com Approved by: ed (mentor, implicit) MFC after: 1 week --- lib/libc/gen/rand48.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/rand48.3 b/lib/libc/gen/rand48.3 index a703ba0..5f6811d 100644 --- a/lib/libc/gen/rand48.3 +++ b/lib/libc/gen/rand48.3 @@ -57,7 +57,7 @@ The particular formula employed is r(n+1) = (a * r(n) + c) mod m where the default values are -for the multiplicand a = 0xfdeece66d = 25214903917 and +for the multiplicand a = 0x5deece66d = 25214903917 and the addend c = 0xb = 11. The modulo is always fixed at m = 2 ** 48. r(n) is called the seed of the random number generator. -- cgit v1.1 From 15e531eab88359053e7ed939c5617ad2e49617b1 Mon Sep 17 00:00:00 2001 From: gavin Date: Tue, 2 Feb 2010 19:44:51 +0000 Subject: Bump .Dd, forgotten in r203393 Approved by: ed (mentor, implicit) MFC after: 1 week --- lib/libc/gen/rand48.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/rand48.3 b/lib/libc/gen/rand48.3 index 5f6811d..8d325a1 100644 --- a/lib/libc/gen/rand48.3 +++ b/lib/libc/gen/rand48.3 @@ -12,7 +12,7 @@ .\" @(#)rand48.3 V1.0 MB 8 Oct 1993 .\" $FreeBSD$ .\" -.Dd October 8, 1993 +.Dd February 2, 2010 .Dt RAND48 3 .Os .Sh NAME -- cgit v1.1 From d0128a84c50db94e8efb99d95578f78e56a2f281 Mon Sep 17 00:00:00 2001 From: rrs Date: Wed, 3 Feb 2010 12:59:44 +0000 Subject: This fixes a bug found and fixed by JC. Basically no save was being done of the ra and gp pointers before we call the __error function. Obtained from: JC (c.jayachandran@gmail.com) --- lib/libc/mips/sys/ptrace.S | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/mips/sys/ptrace.S b/lib/libc/mips/sys/ptrace.S index 86bc1e5..53ca78d 100644 --- a/lib/libc/mips/sys/ptrace.S +++ b/lib/libc/mips/sys/ptrace.S @@ -42,14 +42,26 @@ __FBSDID("$FreeBSD$"); #endif /* LIBC_SCCS and not lint */ LEAF(ptrace) + .frame sp,40,ra + .mask 0x80000000, -8 #ifdef __ABICALLS__ .set noreorder .cpload t9 .set reorder #endif + subu sp, sp, 40 + sw ra, 32(sp) +#ifdef __ABICALLS__ + .cprestore 16 +#endif la t9, _C_LABEL(__error) # locate address of errno - jalr t9 + jalr t9 +#ifdef __ABICALLS__ + lw gp, 16(sp) +#endif sw zero, 0(v0) + lw ra, 32(sp) + addu sp, sp, 40 li v0, SYS_ptrace syscall bne a3, zero, 1f -- cgit v1.1 From 05e2aae4ce58adcfde96b8bd33fa26d4eb47c552 Mon Sep 17 00:00:00 2001 From: ed Date: Wed, 3 Feb 2010 19:31:02 +0000 Subject: Also add a cross-reference to NetBSD updlastlogx(). --- lib/libc/gen/getutxent.3 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/getutxent.3 b/lib/libc/gen/getutxent.3 index 0b29807..5ab21ee 100644 --- a/lib/libc/gen/getutxent.3 +++ b/lib/libc/gen/getutxent.3 @@ -426,8 +426,10 @@ database files, depending on its .Fa ut_type . This prevents the need for special utility functions to update the other databases, such as the +.Fn updlastlogx +and .Fn updwtmpx -function which is often available in other implementations. +functions which are available in other implementations. It also tries to replace .Dv DEAD_PROCESS entries in the active sessions database when storing -- cgit v1.1 From 5946a34d0729306843325f31f709bca2202425e7 Mon Sep 17 00:00:00 2001 From: rrs Date: Wed, 3 Feb 2010 20:54:04 +0000 Subject: -White space cleanup (missing spaces in new line) -Remove extra tab. -Took out the duplicate code that cprestore does. All suggested by Neel. --- lib/libc/mips/sys/ptrace.S | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/mips/sys/ptrace.S b/lib/libc/mips/sys/ptrace.S index 53ca78d..9be54a5 100644 --- a/lib/libc/mips/sys/ptrace.S +++ b/lib/libc/mips/sys/ptrace.S @@ -42,7 +42,7 @@ __FBSDID("$FreeBSD$"); #endif /* LIBC_SCCS and not lint */ LEAF(ptrace) - .frame sp,40,ra + .frame sp, 40, ra .mask 0x80000000, -8 #ifdef __ABICALLS__ .set noreorder @@ -55,10 +55,7 @@ LEAF(ptrace) .cprestore 16 #endif la t9, _C_LABEL(__error) # locate address of errno - jalr t9 -#ifdef __ABICALLS__ - lw gp, 16(sp) -#endif + jalr t9 sw zero, 0(v0) lw ra, 32(sp) addu sp, sp, 40 -- cgit v1.1 From 3e324aa4815e11695da086b862302f3aea9ea7c1 Mon Sep 17 00:00:00 2001 From: neel Date: Thu, 4 Feb 2010 05:49:59 +0000 Subject: Reinstate the ptrace patch to restore the 'gp' register after calling a function. I made a mistake in assuming that the .cprestore directive will cause the assembler to automatically restore 'gp' after the 'jalr'. The .cprestore directive does its magic only after 'jal' and 'bal' instructions - not the 'jalr'. Pointed out by: c.jayachandran@gmail.com --- lib/libc/mips/sys/ptrace.S | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/mips/sys/ptrace.S b/lib/libc/mips/sys/ptrace.S index 9be54a5..09b82c5 100644 --- a/lib/libc/mips/sys/ptrace.S +++ b/lib/libc/mips/sys/ptrace.S @@ -56,6 +56,9 @@ LEAF(ptrace) #endif la t9, _C_LABEL(__error) # locate address of errno jalr t9 +#ifdef __ABICALLS__ + lw gp, 16(sp) +#endif sw zero, 0(v0) lw ra, 32(sp) addu sp, sp, 40 -- cgit v1.1 From 8923df5c26ddfa9cd69e14f78a412c20be8e053b Mon Sep 17 00:00:00 2001 From: ru Date: Thu, 4 Feb 2010 11:23:28 +0000 Subject: Mark up "unsigned char". --- lib/libc/string/memccpy.3 | 4 +++- lib/libc/string/memchr.3 | 3 ++- lib/libc/string/memcmp.3 | 4 +++- lib/libc/string/memset.3 | 4 +++- 4 files changed, 11 insertions(+), 4 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/string/memccpy.3 b/lib/libc/string/memccpy.3 index 350f000..40a25be 100644 --- a/lib/libc/string/memccpy.3 +++ b/lib/libc/string/memccpy.3 @@ -50,7 +50,9 @@ to string .Fa dst . If the character .Fa c -(as converted to an unsigned char) occurs in the string +(as converted to an +.Vt "unsigned char" ) +occurs in the string .Fa src , the copy stops and a pointer to the byte after the copy of .Fa c diff --git a/lib/libc/string/memchr.3 b/lib/libc/string/memchr.3 index ae883bf..6e33aef 100644 --- a/lib/libc/string/memchr.3 +++ b/lib/libc/string/memchr.3 @@ -52,7 +52,8 @@ The function locates the first occurrence of .Fa c -(converted to an unsigned char) +(converted to an +.Vt "unsigned char" ) in string .Fa b . .Pp diff --git a/lib/libc/string/memcmp.3 b/lib/libc/string/memcmp.3 index 507b930..88ed9a2 100644 --- a/lib/libc/string/memcmp.3 +++ b/lib/libc/string/memcmp.3 @@ -61,7 +61,9 @@ The function returns zero if the two strings are identical, otherwise returns the difference between the first two differing bytes -(treated as unsigned char values, so that +(treated as +.Vt "unsigned char" +values, so that .Sq Li \e200 is greater than .Sq Li \&\e0 , diff --git a/lib/libc/string/memset.3 b/lib/libc/string/memset.3 index 1dc287d..07bd7aa 100644 --- a/lib/libc/string/memset.3 +++ b/lib/libc/string/memset.3 @@ -52,7 +52,9 @@ writes .Fa len bytes of value .Fa c -(converted to an unsigned char) to the string +(converted to an +.Vt "unsigned char" ) +to the string .Fa b . .Sh RETURN VALUES The -- cgit v1.1 From 764ce56acec6e1b162434305a36821de3b6e3ded Mon Sep 17 00:00:00 2001 From: marcel Date: Tue, 9 Feb 2010 05:52:35 +0000 Subject: Add PT_VM_TIMESTAMP and PT_VM_ENTRY so that the tracing process can obtain the memory map of the traced process. PT_VM_TIMESTAMP can be used to check if the memory map changed since the last time to avoid iterating over all the VM entries unnecesarily. MFC after: 1 month --- lib/libc/sys/ptrace.2 | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/sys/ptrace.2 b/lib/libc/sys/ptrace.2 index 9d8f550..ab51ee3 100644 --- a/lib/libc/sys/ptrace.2 +++ b/lib/libc/sys/ptrace.2 @@ -2,7 +2,7 @@ .\" $NetBSD: ptrace.2,v 1.2 1995/02/27 12:35:37 cgd Exp $ .\" .\" This file is in the public domain. -.Dd March 27, 2009 +.Dd February 8, 2010 .Dt PTRACE 2 .Os .Sh NAME @@ -327,6 +327,61 @@ This request will trace the specified process on each system call exit. .It PT_SYSCALL This request will trace the specified process on each system call entry and exit. +.It PT_VM_TIMESTAMP +This request returns the generation number or timestamp of the memory map of +the traced process as the return value from +.Fn ptrace . +This provides a low-cost way for the tracing process to determine if the +VM map changed since the last time this request was made. +.It PT_VM_ENTRY +This request is used to iterate over the entries of the VM map of the traced +process. +The +.Fa addr +argument specifies a pointer to a +.Vt "struct ptrace_vm_entry" , +which is defined as follows: +.Bd -literal +struct ptrace_vm_entry { + void *pve_cookie; + u_long pve_start; + u_long pve_end; + u_long pve_offset; + u_int pve_prot; + u_int pve_pathlen; + char *pve_path; +}; +.Ed +.Pp +The first entry is returned by setting +.Va pve_cookie +to +.Dv NULL . +Subsequent entries are returned by leaving +.Va pve_cookie +unmodified from the value returned by previous requests. +By setting +.Va pve_pathlen +to a non-zero value on entry, the pathname of the backing object is returned +in the buffer pointed to by +.Va pve_path , +provided the entry is backed by a vnode. +The +.Va pve_pathlen +field is updated with the actual length of the pathname (including the +terminating null character). +The +.Va pve_offset +field is the offset within the backing object at which the range starts. +The range is located in the VM space at +.Va pve_start +and extends up to +.Va pve_end +(inclusive). +.Pp +The +.Fa data +argument is ignored. .El .Pp Additionally, machine-specific requests can exist. @@ -376,6 +431,10 @@ or .Dv PT_SETDBREGS was attempted on a process with no valid register set. (This is normally true only of system processes.) +.It +.Dv PT_VM_ENTRY +was given an invalid value for +.Fa pve_cookie . .El .It Bq Er EBUSY .Bl -bullet -compact @@ -405,6 +464,22 @@ on a process in violation of the requirements listed under .Dv PT_ATTACH above. .El +.It Bq Er ENOENT +.Bl -bullet -compact +.It +.Dv PT_VM_ENTRY +previously returned the last entry of the memory map. +No more entries exist. +.El +.It Bq Er ENAMETOOLONG +.Bl -bullet -compact +.It +.Dv PT_VM_ENTRY +cannot return the pathname of the backing object because the buffer is not big +enough. +.Fa pve_pathlen +holds the minimum buffer size required on return. +.El .El .Sh SEE ALSO .Xr execve 2 , -- cgit v1.1 From 4081d06fa6ef05970d77dcfc0971dfceeba868cc Mon Sep 17 00:00:00 2001 From: gabor Date: Tue, 9 Feb 2010 19:37:12 +0000 Subject: - Deal with some special cases [1] - style(9) nits Pointed out by: jilles [1] Approved by: delphij (mentor) --- lib/libc/nls/msgcat.c | 84 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 30 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/nls/msgcat.c b/lib/libc/nls/msgcat.c index 0b008ea..910c185 100644 --- a/lib/libc/nls/msgcat.c +++ b/lib/libc/nls/msgcat.c @@ -77,19 +77,22 @@ __FBSDID("$FreeBSD$"); #define NLERR ((nl_catd) -1) #define NLRETERR(errc) { errno = errc; return (NLERR); } -#define SAVEFAIL(n, e) { WLOCK(NLERR); \ - np = malloc(sizeof(struct catentry)); \ - if (np != NULL) { \ - np->name = strdup(n); \ - np->caterrno = e; \ - SLIST_INSERT_HEAD(&cache, np, list); \ - } \ - UNLOCK; \ - } +#define SAVEFAIL(n, l, e) { WLOCK(NLERR); \ + np = malloc(sizeof(struct catentry)); \ + if (np != NULL) { \ + np->name = strdup(n); \ + np->path = NULL; \ + np->lang = (l == NULL) ? NULL : strdup(l); \ + np->caterrno = e; \ + SLIST_INSERT_HEAD(&cache, np, list); \ + } \ + UNLOCK; \ + errno = e; \ + } static nl_catd load_msgcat(const char *, const char *, const char *); -static pthread_rwlock_t rwlock; +static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; struct catentry { SLIST_ENTRY(catentry) list; @@ -114,10 +117,12 @@ catopen(const char *name, int type) int saverr, spcleft; char path[PATH_MAX]; + /* sanity checking */ if (name == NULL || *name == '\0') NLRETERR(EINVAL); if (strchr(name, '/') != NULL) + /* have a pathname */ lang = NULL; else { if (type == NL_CAT_LOCALE) @@ -135,12 +140,14 @@ catopen(const char *name, int type) /* Try to get it from the cache first */ RLOCK(NLERR); SLIST_FOREACH(np, &cache, list) { - if (strcmp(np->name, name) == 0) { + if ((strcmp(np->name, name) == 0) && + ((lang != NULL && np->lang != NULL && + strcmp(np->lang, lang) == 0) || (np->lang == lang))) { if (np->caterrno != 0) { /* Found cached failing entry */ UNLOCK; NLRETERR(np->caterrno); - } else if (strcmp(np->lang, lang) == 0) { + } else { /* Found cached successful entry */ np->refcount++; UNLOCK; @@ -154,6 +161,7 @@ catopen(const char *name, int type) if (strchr(name, '/') != NULL) return (load_msgcat(name, name, lang)); + /* sanity checking */ if ((plang = cptr1 = strdup(lang)) == NULL) return (NLERR); if ((cptr = strchr(cptr1, '@')) != NULL) @@ -218,6 +226,7 @@ catopen(const char *name, int type) too_long: free(plang); free(base); + SAVEFAIL(name, lang, ENAMETOOLONG); NLRETERR(ENAMETOOLONG); } pathP += strlen(tmpptr); @@ -241,6 +250,7 @@ catopen(const char *name, int type) } free(plang); free(base); + SAVEFAIL(name, lang, ENOENT); NLRETERR(ENOENT); } @@ -317,6 +327,7 @@ catclose(nl_catd catd) { struct catentry *np; + /* sanity checking */ if (catd == NULL || catd == NLERR) { errno = EBADF; return (-1); @@ -325,13 +336,15 @@ catclose(nl_catd catd) /* Remove from cache if not referenced any more */ WLOCK(-1); SLIST_FOREACH(np, &cache, list) { - if ((np->catd->__size == catd->__size) && - memcmp((const void *)np->catd, (const void *)catd, np->catd->__size) == 0) { + if (catd == np->catd) { np->refcount--; if (np->refcount == 0) { munmap(catd->__data, (size_t)catd->__size); free(catd); SLIST_REMOVE(&cache, np, catentry, list); + free(np->name); + free(np->path); + free(np->lang); free(np); } break; @@ -357,10 +370,11 @@ load_msgcat(const char *path, const char *name, const char *lang) /* path/name will never be NULL here */ /* One more try in cache; if it was not found by name, - it might still be found by absolute path. */ + * it might still be found by absolute path. + */ RLOCK(NLERR); SLIST_FOREACH(np, &cache, list) { - if (strcmp(np->path, path) == 0) { + if ((np->path != NULL) && (strcmp(np->path, path) == 0)) { np->refcount++; UNLOCK; return (np->catd); @@ -369,36 +383,46 @@ load_msgcat(const char *path, const char *name, const char *lang) UNLOCK; if ((fd = _open(path, O_RDONLY)) == -1) { - SAVEFAIL(name, errno); - return (NLERR); + SAVEFAIL(name, lang, errno); + NLRETERR(errno); } if (_fstat(fd, &st) != 0) { - SAVEFAIL(name, errno); _close(fd); - return (NLERR); + SAVEFAIL(name, lang, EFTYPE); + NLRETERR(EFTYPE); } - data = mmap(0, (size_t)st.st_size, PROT_READ, MAP_FILE|MAP_SHARED, fd, - (off_t)0); - _close(fd); + /* If the file size cannot be held in size_t we cannot mmap() + * it to the memory. Probably, this will not be a problem given + * that catalog files are usually small. + */ + if (st.st_size > SIZE_T_MAX) { + _close(fd); + SAVEFAIL(name, lang, EFBIG); + NLRETERR(EFBIG); + } - if (data == MAP_FAILED) { - SAVEFAIL(name, errno); - return (NLERR); + if ((data = mmap(0, (size_t)st.st_size, PROT_READ, + MAP_FILE|MAP_SHARED, fd, (off_t)0)) == MAP_FAILED) { + int saved_errno = errno; + _close(fd); + SAVEFAIL(name, lang, saved_errno); + NLRETERR(saved_errno); } + _close(fd); if (ntohl((u_int32_t)((struct _nls_cat_hdr *)data)->__magic) != _NLS_MAGIC) { - SAVEFAIL(name, errno); munmap(data, (size_t)st.st_size); - NLRETERR(EINVAL); + SAVEFAIL(name, lang, EFTYPE); + NLRETERR(EFTYPE); } if ((catd = malloc(sizeof (*catd))) == NULL) { - SAVEFAIL(name, errno); munmap(data, (size_t)st.st_size); - return (NLERR); + SAVEFAIL(name, lang, ENOMEM); + NLRETERR(ENOMEM); } catd->__data = data; -- cgit v1.1 From 3d4c1b73b9036a1d5455a4a63eba6e0d20be9350 Mon Sep 17 00:00:00 2001 From: cracauer Date: Wed, 10 Feb 2010 00:02:09 +0000 Subject: Fix PR http://www.freebsd.org/cgi/query-pr.cgi?pr=bin/143350 Empty string test gone wrong. Testing this requires that you have a locale that has the sign string unset but has int_n_sign_posn set (the default locale falls through to use "()" around negative numbers which is probably another bug). I created that setup by hand and indeed without this fix negative numbers are put out as positive numbers (doesn't fall through to use "-" as default indicator). Unfixed example in nl_NL.ISO8859-1 with lc->negative_sign set to empty string: strfmon(buf, sizeof(buf), "%-8i", -42.0); ==> example2: 'EUR 42,00' 'Eu 42,00' Fixed: example2: 'EUR 42,00-' 'Eu 42,00-' This file and suggested fix are identical in at least freebsd-8. Backport might be appropriate but some expert on locales should probably have a look at us defaulting to negative numbers in parenthesis when LC_* is default. That doesn't look right and is not what other OSes are doing. PR: 143350 Submitted by: Corinna Vinschen Reviewed by: bug reporter submitted, tested by me --- lib/libc/stdlib/strfmon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdlib/strfmon.c b/lib/libc/stdlib/strfmon.c index f12c8de..6c28254 100644 --- a/lib/libc/stdlib/strfmon.c +++ b/lib/libc/stdlib/strfmon.c @@ -413,7 +413,7 @@ __setup_vars(int flags, char *cs_precedes, char *sep_by_space, *cs_precedes = lc->int_n_cs_precedes; *sep_by_space = lc->int_n_sep_by_space; *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->int_n_sign_posn; - *signstr = (lc->negative_sign == '\0') ? "-" + *signstr = (lc->negative_sign[0] == '\0') ? "-" : lc->negative_sign; } else if (flags & USE_INTL_CURRENCY) { *cs_precedes = lc->int_p_cs_precedes; @@ -424,7 +424,7 @@ __setup_vars(int flags, char *cs_precedes, char *sep_by_space, *cs_precedes = lc->n_cs_precedes; *sep_by_space = lc->n_sep_by_space; *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->n_sign_posn; - *signstr = (lc->negative_sign == '\0') ? "-" + *signstr = (lc->negative_sign[0] == '\0') ? "-" : lc->negative_sign; } else { *cs_precedes = lc->p_cs_precedes; -- cgit v1.1 From 2f0d28019151229e89de6b5850ef0fdb6e53f473 Mon Sep 17 00:00:00 2001 From: trhodes Date: Thu, 11 Feb 2010 14:45:00 +0000 Subject: Correct two typoes. Submitted by: Matthew Seaman --- lib/libc/posix1e/mac.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/posix1e/mac.3 b/lib/libc/posix1e/mac.3 index c570998..d95d489 100644 --- a/lib/libc/posix1e/mac.3 +++ b/lib/libc/posix1e/mac.3 @@ -155,7 +155,7 @@ system objects, but without policy-specific knowledge. These APIs are loosely based on the APIs described in POSIX.1e, as described in IEEE POSIX.1e draft 17. However, the resemblence of these APIS to the POSIX APIs is loose, as the -PSOXI APIS were unable to express some notinos required for flexible and +POSIX APIS were unable to express some notions required for flexible and extensible access control. .Sh HISTORY Support for Mandatory Access Control was introduced in -- cgit v1.1 From 59fa82c67cc9d19caf2b05c781ed2b3b9101697f Mon Sep 17 00:00:00 2001 From: marcel Date: Thu, 11 Feb 2010 18:00:53 +0000 Subject: o Add support for COMPAT_IA32. o Incorporate review comments: - Properly reference and lock the map - Take into account that the VM map can change inbetween requests - Add the fileid and fsid attributes Credits: kib@ Reviewed by: kib@ --- lib/libc/sys/ptrace.2 | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/sys/ptrace.2 b/lib/libc/sys/ptrace.2 index ab51ee3..8265fb6 100644 --- a/lib/libc/sys/ptrace.2 +++ b/lib/libc/sys/ptrace.2 @@ -2,7 +2,7 @@ .\" $NetBSD: ptrace.2,v 1.2 1995/02/27 12:35:37 cgd Exp $ .\" .\" This file is in the public domain. -.Dd February 8, 2010 +.Dd February 11, 2010 .Dt PTRACE 2 .Os .Sh NAME @@ -343,23 +343,30 @@ argument specifies a pointer to a which is defined as follows: .Bd -literal struct ptrace_vm_entry { - void *pve_cookie; - u_long pve_start; - u_long pve_end; - u_long pve_offset; - u_int pve_prot; - u_int pve_pathlen; - char *pve_path; + int pve_entry; + int pve_timestamp; + u_long pve_start; + u_long pve_end; + u_long pve_offset; + u_int pve_prot; + u_int pve_pathlen; + long pve_fileid; + uint32_t pve_fsid; + char *pve_path; }; .Ed .Pp The first entry is returned by setting -.Va pve_cookie -to -.Dv NULL . +.Va pve_entry +to zero. Subsequent entries are returned by leaving -.Va pve_cookie +.Va pve_entry unmodified from the value returned by previous requests. +The +.Va pve_timestamp +field can be used to detect changes to the VM map while iterating over the +entries. +The tracing process can then take appropriate action, such as restarting. By setting .Va pve_pathlen to a non-zero value on entry, the pathname of the backing object is returned @@ -434,7 +441,8 @@ was attempted on a process with no valid register set. .It .Dv PT_VM_ENTRY was given an invalid value for -.Fa pve_cookie . +.Fa pve_entry . +This can also be caused by changes to the VM map of the process. .El .It Bq Er EBUSY .Bl -bullet -compact -- cgit v1.1 From 9aa063fee42f5bde6ae89a7f079d7483b977629e Mon Sep 17 00:00:00 2001 From: trhodes Date: Thu, 11 Feb 2010 19:20:06 +0000 Subject: s/APIS/APIs - not part of the original submission. --- lib/libc/posix1e/mac.3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/posix1e/mac.3 b/lib/libc/posix1e/mac.3 index d95d489..6499d6b 100644 --- a/lib/libc/posix1e/mac.3 +++ b/lib/libc/posix1e/mac.3 @@ -154,8 +154,8 @@ system objects, but without policy-specific knowledge. .Sh STANDARDS These APIs are loosely based on the APIs described in POSIX.1e, as described in IEEE POSIX.1e draft 17. -However, the resemblence of these APIS to the POSIX APIs is loose, as the -POSIX APIS were unable to express some notions required for flexible and +However, the resemblence of these APIs to the POSIX APIs is loose, as the +POSIX APIs were unable to express some notions required for flexible and extensible access control. .Sh HISTORY Support for Mandatory Access Control was introduced in -- cgit v1.1 From 56cf56f59df60dc691d2efd078049223c846a9e6 Mon Sep 17 00:00:00 2001 From: marcel Date: Tue, 16 Feb 2010 02:22:59 +0000 Subject: The static TLS size as given by tls_static_space includes TLS_TCB_SIZE bytes of TCB in variant I. --- lib/libc/gen/tls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/tls.c b/lib/libc/gen/tls.c index 2756e94..9d84679 100644 --- a/lib/libc/gen/tls.c +++ b/lib/libc/gen/tls.c @@ -137,11 +137,11 @@ __libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign __unused) if (oldtcb != NULL && tcbsize == TLS_TCB_SIZE) return (oldtcb); - tcb = calloc(1, tls_static_space + tcbsize); + tcb = calloc(1, tls_static_space + tcbsize - TLS_TCB_SIZE); tls = (Elf_Addr **)(tcb + tcbsize - TLS_TCB_SIZE); if (oldtcb != NULL) { - memcpy(tls, oldtcb, tls_static_space + TLS_TCB_SIZE); + memcpy(tls, oldtcb, tls_static_space); free(oldtcb); /* Adjust the DTV. */ -- cgit v1.1 From b3a749c0d1ec76a6d6db15266cc3819ac868be53 Mon Sep 17 00:00:00 2001 From: marcel Date: Tue, 16 Feb 2010 06:47:00 +0000 Subject: Unbreak ia64: tls_model("initial-exec") is invalid, because it assumes the static TLS model, which is fundamentally different from the dynamic TLS model. The consequence was data corruption. Limit the attribute to i386 and amd64. --- lib/libc/stdlib/malloc.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c index f91220e..5abcca9 100644 --- a/lib/libc/stdlib/malloc.c +++ b/lib/libc/stdlib/malloc.c @@ -215,10 +215,12 @@ __FBSDID("$FreeBSD$"); # define LG_QUANTUM 4 # define LG_SIZEOF_PTR 2 # define CPU_SPINWAIT __asm__ volatile("pause") +# define TLS_MODEL __attribute__((tls_model("initial-exec"))) #endif #ifdef __ia64__ # define LG_QUANTUM 4 # define LG_SIZEOF_PTR 3 +# define TLS_MODEL /* default */ #endif #ifdef __alpha__ # define LG_QUANTUM 4 @@ -234,6 +236,7 @@ __FBSDID("$FreeBSD$"); # define LG_QUANTUM 4 # define LG_SIZEOF_PTR 3 # define CPU_SPINWAIT __asm__ volatile("pause") +# define TLS_MODEL __attribute__((tls_model("initial-exec"))) #endif #ifdef __arm__ # define LG_QUANTUM 3 @@ -1090,14 +1093,12 @@ static pthread_mutex_t arenas_lock; /* Protects arenas initialization. */ * Map of _pthread_self() --> arenas[???], used for selecting an arena to use * for allocations. */ -static __thread arena_t *arenas_map - __attribute__((tls_model("initial-exec"))); +static __thread arena_t *arenas_map TLS_MODEL; #endif #ifdef MALLOC_TCACHE /* Map of thread-specific caches. */ -static __thread tcache_t *tcache_tls - __attribute__((tls_model("initial-exec"))); +static __thread tcache_t *tcache_tls TLS_MODEL; /* * Number of cache slots for each bin in the thread cache, or 0 if tcache is @@ -1115,15 +1116,12 @@ unsigned tcache_gc_incr; * since the state of mmap_unaligned only affects performance, rather than * correct function. */ -static #ifndef NO_TLS - __thread -#endif - bool mmap_unaligned -#ifndef NO_TLS - __attribute__((tls_model("initial-exec"))) +static __thread bool mmap_unaligned TLS_MODEL; +#else +static bool mmap_unaligned; #endif - ; + #ifdef MALLOC_STATS static malloc_mutex_t chunks_mtx; /* Chunk statistics. */ -- cgit v1.1 From 35a8cfd727ff0f4cd768960a8dd62e62a0b2c785 Mon Sep 17 00:00:00 2001 From: ru Date: Tue, 16 Feb 2010 12:29:02 +0000 Subject: %U was macroized in mdoc(7), escape. --- lib/libc/stdio/printf.3 | 2 +- lib/libc/stdtime/strptime.3 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdio/printf.3 b/lib/libc/stdio/printf.3 index 2587aa2..8de2bb8 100644 --- a/lib/libc/stdio/printf.3 +++ b/lib/libc/stdio/printf.3 @@ -812,7 +812,7 @@ available. The conversion formats .Cm \&%D , \&%O , and -.Cm %U +.Cm \&%U are not standard and are provided only for backward compatibility. The effect of padding the diff --git a/lib/libc/stdtime/strptime.3 b/lib/libc/stdtime/strptime.3 index d763fbc..763696b 100644 --- a/lib/libc/stdtime/strptime.3 +++ b/lib/libc/stdtime/strptime.3 @@ -149,7 +149,7 @@ and 12PM is taken as noon. .Pp The -.Fa %U +.Fa \&%U and .Fa %W format specifiers accept any value within the range 00 to 53 -- cgit v1.1 From bf1afdcf619a66af0c903f89f5061b72ab572330 Mon Sep 17 00:00:00 2001 From: marcel Date: Tue, 16 Feb 2010 20:46:22 +0000 Subject: Define TLS_MODEL for PowerPC as well. Since PowerPC uses variant I, like ia64, leave it empty (default model). --- lib/libc/stdlib/malloc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/libc') diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c index 5abcca9..de7a4c0 100644 --- a/lib/libc/stdlib/malloc.c +++ b/lib/libc/stdlib/malloc.c @@ -250,6 +250,7 @@ __FBSDID("$FreeBSD$"); #endif #ifdef __powerpc__ # define LG_QUANTUM 4 +# define TLS_MODEL /* default */ #endif #ifdef __s390x__ # define LG_QUANTUM 4 -- cgit v1.1 From 41471022dccbc47ade8bd73eb015bcf9337ce3a3 Mon Sep 17 00:00:00 2001 From: phk Date: Wed, 17 Feb 2010 09:11:21 +0000 Subject: Mention EISDIR as a possible errno. --- lib/libc/sys/unlink.2 | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/sys/unlink.2 b/lib/libc/sys/unlink.2 index 41a2288..141f3d3 100644 --- a/lib/libc/sys/unlink.2 +++ b/lib/libc/sys/unlink.2 @@ -114,6 +114,8 @@ succeeds unless: .Bl -tag -width Er .It Bq Er ENOTDIR A component of the path prefix is not a directory. +.It Bq Er EISDIR +The named file is a directory. .It Bq Er ENAMETOOLONG A component of a pathname exceeded 255 characters, or an entire path name exceeded 1023 characters. -- cgit v1.1 From ea21a95532c9b4b4f4ea01448d6beaa75813d377 Mon Sep 17 00:00:00 2001 From: gabor Date: Sat, 20 Feb 2010 08:19:19 +0000 Subject: - More style(9) fixups Approved by: delphij (mentor) --- lib/libc/nls/msgcat.c | 55 +++++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 26 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/nls/msgcat.c b/lib/libc/nls/msgcat.c index 910c185..4532e90 100644 --- a/lib/libc/nls/msgcat.c +++ b/lib/libc/nls/msgcat.c @@ -60,34 +60,35 @@ __FBSDID("$FreeBSD$"); #define _DEFAULT_NLS_PATH "/usr/share/nls/%L/%N.cat:/usr/share/nls/%N/%L:/usr/local/share/nls/%L/%N.cat:/usr/local/share/nls/%N/%L" -#define RLOCK(fail) { int ret; \ - if (__isthreaded && \ - ((ret = _pthread_rwlock_rdlock(&rwlock)) != 0)) { \ - errno = ret; \ - return (fail); \ +#define RLOCK(fail) { int ret; \ + if (__isthreaded && \ + ((ret = _pthread_rwlock_rdlock(&rwlock)) != 0)) { \ + errno = ret; \ + return (fail); \ }} -#define WLOCK(fail) { int ret; \ - if (__isthreaded && \ - ((ret = _pthread_rwlock_wrlock(&rwlock)) != 0)) { \ - errno = ret; \ - return (fail); \ +#define WLOCK(fail) { int ret; \ + if (__isthreaded && \ + ((ret = _pthread_rwlock_wrlock(&rwlock)) != 0)) { \ + errno = ret; \ + return (fail); \ }} -#define UNLOCK { if (__isthreaded) \ +#define UNLOCK { if (__isthreaded) \ _pthread_rwlock_unlock(&rwlock); } #define NLERR ((nl_catd) -1) #define NLRETERR(errc) { errno = errc; return (NLERR); } -#define SAVEFAIL(n, l, e) { WLOCK(NLERR); \ - np = malloc(sizeof(struct catentry)); \ - if (np != NULL) { \ - np->name = strdup(n); \ - np->path = NULL; \ - np->lang = (l == NULL) ? NULL : strdup(l); \ - np->caterrno = e; \ - SLIST_INSERT_HEAD(&cache, np, list); \ - } \ - UNLOCK; \ - errno = e; \ +#define SAVEFAIL(n, l, e) { WLOCK(NLERR); \ + np = malloc(sizeof(struct catentry)); \ + if (np != NULL) { \ + np->name = strdup(n); \ + np->path = NULL; \ + np->lang = (l == NULL) ? NULL : \ + strdup(l); \ + np->caterrno = e; \ + SLIST_INSERT_HEAD(&cache, np, list); \ + } \ + UNLOCK; \ + errno = e; \ } static nl_catd load_msgcat(const char *, const char *, const char *); @@ -209,7 +210,7 @@ catopen(const char *name, int type) break; case '%': ++nlspath; - /* fallthrough */ + /* FALLTHROUGH */ default: if (pathP - path >= sizeof(path) - 1) @@ -369,7 +370,8 @@ load_msgcat(const char *path, const char *name, const char *lang) /* path/name will never be NULL here */ - /* One more try in cache; if it was not found by name, + /* + * One more try in cache; if it was not found by name, * it might still be found by absolute path. */ RLOCK(NLERR); @@ -393,8 +395,9 @@ load_msgcat(const char *path, const char *name, const char *lang) NLRETERR(EFTYPE); } - /* If the file size cannot be held in size_t we cannot mmap() - * it to the memory. Probably, this will not be a problem given + /* + * If the file size cannot be held in size_t we cannot mmap() + * it to the memory. Probably, this will not be a problem given * that catalog files are usually small. */ if (st.st_size > SIZE_T_MAX) { -- cgit v1.1 From 1fdea921e1450bf99dc432803cd6c88e08540a21 Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 21 Feb 2010 13:57:02 +0000 Subject: Add proper const keywords to sysctl(3) parameters. The `name' and `newp' arguments can be marked const, because the buffers they refer to are never changed. While there, perform some other cleanups: - Remove K&R from sysctl.c. - Implement sysctlbyname() using sysctlnametomib() to prevent duplication of an undocumented kernel interface. - Fix some whitespace nits. It seems the prototypes are now in sync with NetBSD as well. --- lib/libc/gen/sysctl.3 | 6 +++--- lib/libc/gen/sysctl.c | 11 ++++------- lib/libc/gen/sysctlbyname.c | 17 +++++------------ lib/libc/gen/sysctlnametomib.c | 6 +++--- 4 files changed, 15 insertions(+), 25 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/sysctl.3 b/lib/libc/gen/sysctl.3 index 75f8668..143be16 100644 --- a/lib/libc/gen/sysctl.3 +++ b/lib/libc/gen/sysctl.3 @@ -28,7 +28,7 @@ .\" @(#)sysctl.3 8.4 (Berkeley) 5/9/95 .\" $FreeBSD$ .\" -.Dd January 28, 2009 +.Dd February 21, 2010 .Dt SYSCTL 3 .Os .Sh NAME @@ -42,9 +42,9 @@ .In sys/types.h .In sys/sysctl.h .Ft int -.Fn sysctl "int *name" "u_int namelen" "void *oldp" "size_t *oldlenp" "void *newp" "size_t newlen" +.Fn sysctl "const int *name" "u_int namelen" "void *oldp" "size_t *oldlenp" "const void *newp" "size_t newlen" .Ft int -.Fn sysctlbyname "const char *name" "void *oldp" "size_t *oldlenp" "void *newp" "size_t newlen" +.Fn sysctlbyname "const char *name" "void *oldp" "size_t *oldlenp" "const void *newp" "size_t newlen" .Ft int .Fn sysctlnametomib "const char *name" "int *mibp" "size_t *sizep" .Sh DESCRIPTION diff --git a/lib/libc/gen/sysctl.c b/lib/libc/gen/sysctl.c index eb6418e..fbc2c0c 100644 --- a/lib/libc/gen/sysctl.c +++ b/lib/libc/gen/sysctl.c @@ -43,15 +43,12 @@ __FBSDID("$FreeBSD$"); #include #include -extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, - void *newp, size_t newlen); +extern int __sysctl(const int *name, u_int namelen, void *oldp, + size_t *oldlenp, const void *newp, size_t newlen); int -sysctl(name, namelen, oldp, oldlenp, newp, newlen) - int *name; - u_int namelen; - void *oldp, *newp; - size_t *oldlenp, newlen; +sysctl(const int *name, u_int namelen, void *oldp, size_t *oldlenp, + const void *newp, size_t newlen) { if (name[0] != CTL_USER) return (__sysctl(name, namelen, oldp, oldlenp, newp, newlen)); diff --git a/lib/libc/gen/sysctlbyname.c b/lib/libc/gen/sysctlbyname.c index 4510fe0..0288d87 100644 --- a/lib/libc/gen/sysctlbyname.c +++ b/lib/libc/gen/sysctlbyname.c @@ -13,26 +13,19 @@ __FBSDID("$FreeBSD$"); #include #include -#include int -sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, - size_t newlen) +sysctlbyname(const char *name, void *oldp, size_t *oldlenp, + const void *newp, size_t newlen) { - int name2oid_oid[2]; int real_oid[CTL_MAXNAME+2]; int error; size_t oidlen; - name2oid_oid[0] = 0; /* This is magic & undocumented! */ - name2oid_oid[1] = 3; - - oidlen = sizeof(real_oid); - error = sysctl(name2oid_oid, 2, real_oid, &oidlen, (void *)name, - strlen(name)); + oidlen = sizeof(real_oid) / sizeof(int); + error = sysctlnametomib(name, real_oid, &oidlen); if (error < 0) - return error; - oidlen /= sizeof (int); + return (error); error = sysctl(real_oid, oidlen, oldp, oldlenp, newp, newlen); return (error); } diff --git a/lib/libc/gen/sysctlnametomib.c b/lib/libc/gen/sysctlnametomib.c index 1515784..afca95d 100644 --- a/lib/libc/gen/sysctlnametomib.c +++ b/lib/libc/gen/sysctlnametomib.c @@ -48,8 +48,8 @@ sysctlnametomib(const char *name, int *mibp, size_t *sizep) oid[0] = 0; oid[1] = 3; - *sizep *= sizeof (int); - error = sysctl(oid, 2, mibp, sizep, (void *)name, strlen(name)); - *sizep /= sizeof (int); + *sizep *= sizeof(int); + error = sysctl(oid, 2, mibp, sizep, name, strlen(name)); + *sizep /= sizeof(int); return (error); } -- cgit v1.1 From 2235c1c97aa6f008916ba47b053639a3c9814dc9 Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 21 Feb 2010 14:58:01 +0000 Subject: While there, trim some trailing whitespace. --- lib/libc/gen/sysctlbyname.c | 1 - 1 file changed, 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/sysctlbyname.c b/lib/libc/gen/sysctlbyname.c index 0288d87..a2e0d5f 100644 --- a/lib/libc/gen/sysctlbyname.c +++ b/lib/libc/gen/sysctlbyname.c @@ -29,4 +29,3 @@ sysctlbyname(const char *name, void *oldp, size_t *oldlenp, error = sysctl(real_oid, oidlen, oldp, oldlenp, newp, newlen); return (error); } - -- cgit v1.1 From e2b46d611bb185c62d8f4cc41b874a385e7916b9 Mon Sep 17 00:00:00 2001 From: kib Date: Thu, 25 Feb 2010 13:51:11 +0000 Subject: Make pause(3) implementation not depended on the legacy sigcompat.c interfaces. Do not block rt signals during and after pause(3) calls. Use private libc namespace to call proper methods. MFC after: 1 week --- lib/libc/gen/pause.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'lib/libc') diff --git a/lib/libc/gen/pause.c b/lib/libc/gen/pause.c index 00bf833..51706cf 100644 --- a/lib/libc/gen/pause.c +++ b/lib/libc/gen/pause.c @@ -33,8 +33,10 @@ static char sccsid[] = "@(#)pause.c 8.1 (Berkeley) 6/4/93"; #include __FBSDID("$FreeBSD$"); +#include "namespace.h" #include #include +#include "un-namespace.h" /* * Backwards compatible pause. @@ -42,7 +44,11 @@ __FBSDID("$FreeBSD$"); int __pause(void) { - return sigpause(sigblock(0L)); + sigset_t oset; + + if (_sigprocmask(SIG_BLOCK, NULL, &oset) == -1) + return (-1); + return (_sigsuspend(&oset)); } __weak_reference(__pause, pause); __weak_reference(__pause, _pause); -- cgit v1.1 From 055b8f69dc6fd8686f311f894d70d88649a763c2 Mon Sep 17 00:00:00 2001 From: edwin Date: Fri, 26 Feb 2010 06:44:00 +0000 Subject: Split the contributed code from libc/stdtime from lib/libc/stdtime to contrib/tzcode/stdtime. --- lib/libc/gen/sysconf.c | 2 +- lib/libc/stdtime/Makefile.inc | 5 +- lib/libc/stdtime/asctime.c | 142 --- lib/libc/stdtime/ctime.3 | 374 ------- lib/libc/stdtime/difftime.c | 69 -- lib/libc/stdtime/localtime.c | 2249 ----------------------------------------- lib/libc/stdtime/private.h | 326 ------ lib/libc/stdtime/time2posix.3 | 123 --- lib/libc/stdtime/tzfile.5 | 152 --- lib/libc/stdtime/tzfile.h | 184 ---- 10 files changed, 5 insertions(+), 3621 deletions(-) delete mode 100644 lib/libc/stdtime/asctime.c delete mode 100644 lib/libc/stdtime/ctime.3 delete mode 100644 lib/libc/stdtime/difftime.c delete mode 100644 lib/libc/stdtime/localtime.c delete mode 100644 lib/libc/stdtime/private.h delete mode 100644 lib/libc/stdtime/time2posix.3 delete mode 100644 lib/libc/stdtime/tzfile.5 delete mode 100644 lib/libc/stdtime/tzfile.h (limited to 'lib/libc') diff --git a/lib/libc/gen/sysconf.c b/lib/libc/gen/sysconf.c index 3c342ee..4618f32 100644 --- a/lib/libc/gen/sysconf.c +++ b/lib/libc/gen/sysconf.c @@ -50,7 +50,7 @@ __FBSDID("$FreeBSD$"); #include #include "../stdlib/atexit.h" -#include "../stdtime/tzfile.h" +#include "tzfile.h" /* from ../../../contrib/tzcode/stdtime */ #define _PATH_ZONEINFO TZDIR /* from tzfile.h */ diff --git a/lib/libc/stdtime/Makefile.inc b/lib/libc/stdtime/Makefile.inc index a58a8a2..a039bc9 100644 --- a/lib/libc/stdtime/Makefile.inc +++ b/lib/libc/stdtime/Makefile.inc @@ -1,13 +1,16 @@ # Makefile.inc,v 1.2 1994/09/13 21:26:01 wollman Exp # $FreeBSD$ -.PATH: ${.CURDIR}/stdtime ${.CURDIR}/../locale +.PATH: ${.CURDIR}/stdtime ${.CURDIR}/../locale \ + ${.CURDIR}/../../contrib/tzcode/stdtime SRCS+= asctime.c difftime.c localtime.c strftime.c strptime.c timelocal.c \ time32.c SYM_MAPS+= ${.CURDIR}/stdtime/Symbol.map +CFLAGS+= -I${.CURDIR}/../../contrib/tzcode/stdtime -I${.CURDIR}/stdtime + MAN+= ctime.3 strftime.3 strptime.3 time2posix.3 MAN+= tzfile.5 diff --git a/lib/libc/stdtime/asctime.c b/lib/libc/stdtime/asctime.c deleted file mode 100644 index 30606f1..0000000 --- a/lib/libc/stdtime/asctime.c +++ /dev/null @@ -1,142 +0,0 @@ -/* -** This file is in the public domain, so clarified as of -** 1996-06-05 by Arthur David Olson. -*/ - -/* -** Avoid the temptation to punt entirely to strftime; -** the output of strftime is supposed to be locale specific -** whereas the output of asctime is supposed to be constant. -*/ - -#include -#ifndef lint -#ifndef NOID -static char elsieid[] __unused = "@(#)asctime.c 8.2"; -#endif /* !defined NOID */ -#endif /* !defined lint */ -__FBSDID("$FreeBSD$"); - -/*LINTLIBRARY*/ - -#include "namespace.h" -#include "private.h" -#include "un-namespace.h" -#include "tzfile.h" - -/* -** Some systems only handle "%.2d"; others only handle "%02d"; -** "%02.2d" makes (most) everybody happy. -** At least some versions of gcc warn about the %02.2d; -** we conditionalize below to avoid the warning. -*/ -/* -** All years associated with 32-bit time_t values are exactly four digits long; -** some years associated with 64-bit time_t values are not. -** Vintage programs are coded for years that are always four digits long -** and may assume that the newline always lands in the same place. -** For years that are less than four digits, we pad the output with -** leading zeroes to get the newline in the traditional place. -** The -4 ensures that we get four characters of output even if -** we call a strftime variant that produces fewer characters for some years. -** The ISO C 1999 and POSIX 1003.1-2004 standards prohibit padding the year, -** but many implementations pad anyway; most likely the standards are buggy. -*/ -#ifdef __GNUC__ -#define ASCTIME_FMT "%.3s %.3s%3d %2.2d:%2.2d:%2.2d %-4s\n" -#else /* !defined __GNUC__ */ -#define ASCTIME_FMT "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %-4s\n" -#endif /* !defined __GNUC__ */ -/* -** For years that are more than four digits we put extra spaces before the year -** so that code trying to overwrite the newline won't end up overwriting -** a digit within a year and truncating the year (operating on the assumption -** that no output is better than wrong output). -*/ -#ifdef __GNUC__ -#define ASCTIME_FMT_B "%.3s %.3s%3d %2.2d:%2.2d:%2.2d %s\n" -#else /* !defined __GNUC__ */ -#define ASCTIME_FMT_B "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %s\n" -#endif /* !defined __GNUC__ */ - -#define STD_ASCTIME_BUF_SIZE 26 -/* -** Big enough for something such as -** ??? ???-2147483648 -2147483648:-2147483648:-2147483648 -2147483648\n -** (two three-character abbreviations, five strings denoting integers, -** seven explicit spaces, two explicit colons, a newline, -** and a trailing ASCII nul). -** The values above are for systems where an int is 32 bits and are provided -** as an example; the define below calculates the maximum for the system at -** hand. -*/ -#define MAX_ASCTIME_BUF_SIZE (2*3+5*INT_STRLEN_MAXIMUM(int)+7+2+1+1) - -static char buf_asctime[MAX_ASCTIME_BUF_SIZE]; - -/* -** A la ISO/IEC 9945-1, ANSI/IEEE Std 1003.1, 2004 Edition. -*/ - -char * -asctime_r(timeptr, buf) -const struct tm * timeptr; -char * buf; -{ - static const char wday_name[][3] = { - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" - }; - static const char mon_name[][3] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }; - const char * wn; - const char * mn; - char year[INT_STRLEN_MAXIMUM(int) + 2]; - char result[MAX_ASCTIME_BUF_SIZE]; - - if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK) - wn = "???"; - else wn = wday_name[timeptr->tm_wday]; - if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR) - mn = "???"; - else mn = mon_name[timeptr->tm_mon]; - /* - ** Use strftime's %Y to generate the year, to avoid overflow problems - ** when computing timeptr->tm_year + TM_YEAR_BASE. - ** Assume that strftime is unaffected by other out-of-range members - ** (e.g., timeptr->tm_mday) when processing "%Y". - */ - (void) strftime(year, sizeof year, "%Y", timeptr); - /* - ** We avoid using snprintf since it's not available on all systems. - */ - (void) sprintf(result, - ((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B), - wn, mn, - timeptr->tm_mday, timeptr->tm_hour, - timeptr->tm_min, timeptr->tm_sec, - year); - if (strlen(result) < STD_ASCTIME_BUF_SIZE || buf == buf_asctime) { - (void) strcpy(buf, result); - return buf; - } else { -#ifdef EOVERFLOW - errno = EOVERFLOW; -#else /* !defined EOVERFLOW */ - errno = EINVAL; -#endif /* !defined EOVERFLOW */ - return NULL; - } -} - -/* -** A la ISO/IEC 9945-1, ANSI/IEEE Std 1003.1, 2004 Edition. -*/ - -char * -asctime(timeptr) -const struct tm * timeptr; -{ - return asctime_r(timeptr, buf_asctime); -} diff --git a/lib/libc/stdtime/ctime.3 b/lib/libc/stdtime/ctime.3 deleted file mode 100644 index 143bc2c..0000000 --- a/lib/libc/stdtime/ctime.3 +++ /dev/null @@ -1,374 +0,0 @@ -.\" Copyright (c) 1989, 1991, 1993 -.\" The Regents of the University of California. All rights reserved. -.\" -.\" This code is derived from software contributed to Berkeley by -.\" Arthur Olson. -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 4. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" From: @(#)ctime.3 8.1 (Berkeley) 6/4/93 -.\" $FreeBSD$ -.\" -.Dd January 2, 1999 -.Dt CTIME 3 -.Os -.Sh NAME -.Nm asctime , -.Nm asctime_r , -.Nm ctime , -.Nm ctime_r , -.Nm difftime , -.Nm gmtime , -.Nm gmtime_r , -.Nm localtime , -.Nm localtime_r , -.Nm mktime , -.Nm timegm -.Nd transform binary date and time values -.Sh LIBRARY -.Lb libc -.Sh SYNOPSIS -.In time.h -.Vt extern char *tzname[2] ; -.Ft char * -.Fn ctime "const time_t *clock" -.Ft double -.Fn difftime "time_t time1" "time_t time0" -.Ft char * -.Fn asctime "const struct tm *tm" -.Ft struct tm * -.Fn localtime "const time_t *clock" -.Ft struct tm * -.Fn gmtime "const time_t *clock" -.Ft time_t -.Fn mktime "struct tm *tm" -.Ft time_t -.Fn timegm "struct tm *tm" -.Ft char * -.Fn ctime_r "const time_t *clock" "char *buf" -.Ft struct tm * -.Fn localtime_r "const time_t *clock" "struct tm *result" -.Ft struct tm * -.Fn gmtime_r "const time_t *clock" "struct tm *result" -.Ft char * -.Fn asctime_r "const struct tm *tm" "char *buf" -.Sh DESCRIPTION -The functions -.Fn ctime , -.Fn gmtime -and -.Fn localtime -all take as an argument a time value representing the time in seconds since -the Epoch (00:00:00 -.Tn UTC , -January 1, 1970; see -.Xr time 3 ) . -.Pp -The function -.Fn localtime -converts the time value pointed at by -.Fa clock , -and returns a pointer to a -.Dq Fa struct tm -(described below) which contains -the broken-out time information for the value after adjusting for the current -time zone (and any other factors such as Daylight Saving Time). -Time zone adjustments are performed as specified by the -.Ev TZ -environment variable (see -.Xr tzset 3 ) . -The function -.Fn localtime -uses -.Xr tzset 3 -to initialize time conversion information if -.Xr tzset 3 -has not already been called by the process. -.Pp -After filling in the tm structure, -.Fn localtime -sets the -.Fa tm_isdst Ns 'th -element of -.Fa tzname -to a pointer to an -.Tn ASCII -string that is the time zone abbreviation to be -used with -.Fn localtime Ns 's -return value. -.Pp -The function -.Fn gmtime -similarly converts the time value, but without any time zone adjustment, -and returns a pointer to a tm structure (described below). -.Pp -The -.Fn ctime -function -adjusts the time value for the current time zone in the same manner as -.Fn localtime , -and returns a pointer to a 26-character string of the form: -.Bd -literal -offset indent -Thu Nov 24 18:22:48 1986\en\e0 -.Ed -.Pp -All the fields have constant width. -.Pp -The -.Fn ctime_r -function -provides the same functionality as -.Fn ctime -except the caller must provide the output buffer -.Fa buf -to store the result, which must be at least 26 characters long. -The -.Fn localtime_r -and -.Fn gmtime_r -functions -provide the same functionality as -.Fn localtime -and -.Fn gmtime -respectively, except the caller must provide the output buffer -.Fa result . -.Pp -The -.Fn asctime -function -converts the broken down time in the structure -.Fa tm -pointed at by -.Fa *tm -to the form -shown in the example above. -.Pp -The -.Fn asctime_r -function -provides the same functionality as -.Fn asctime -except the caller provide the output buffer -.Fa buf -to store the result, which must be at least 26 characters long. -.Pp -The functions -.Fn mktime -and -.Fn timegm -convert the broken-down time in the structure -pointed to by tm into a time value with the same encoding as that of the -values returned by the -.Xr time 3 -function (that is, seconds from the Epoch, -.Tn UTC ) . -The -.Fn mktime -function -interprets the input structure according to the current timezone setting -(see -.Xr tzset 3 ) . -The -.Fn timegm -function -interprets the input structure as representing Universal Coordinated Time -.Pq Tn UTC . -.Pp -The original values of the -.Fa tm_wday -and -.Fa tm_yday -components of the structure are ignored, and the original values of the -other components are not restricted to their normal ranges, and will be -normalized if needed. -For example, -October 40 is changed into November 9, -a -.Fa tm_hour -of \-1 means 1 hour before midnight, -.Fa tm_mday -of 0 means the day preceding the current month, and -.Fa tm_mon -of \-2 means 2 months before January of -.Fa tm_year . -(A positive or zero value for -.Fa tm_isdst -causes -.Fn mktime -to presume initially that summer time (for example, Daylight Saving Time) -is or is not in effect for the specified time, respectively. -A negative value for -.Fa tm_isdst -causes the -.Fn mktime -function to attempt to divine whether summer time is in effect for the -specified time. -The -.Fa tm_isdst -and -.Fa tm_gmtoff -members are forced to zero by -.Fn timegm . ) -.Pp -On successful completion, the values of the -.Fa tm_wday -and -.Fa tm_yday -components of the structure are set appropriately, and the other components -are set to represent the specified calendar time, but with their values -forced to their normal ranges; the final value of -.Fa tm_mday -is not set until -.Fa tm_mon -and -.Fa tm_year -are determined. -The -.Fn mktime -function -returns the specified calendar time; if the calendar time cannot be -represented, it returns \-1; -.Pp -The -.Fn difftime -function -returns the difference between two calendar times, -.Pf ( Fa time1 -- -.Fa time0 ) , -expressed in seconds. -.Pp -External declarations as well as the tm structure definition are in the -.In time.h -include file. -The tm structure includes at least the following fields: -.Bd -literal -offset indent -int tm_sec; /\(** seconds (0 - 60) \(**/ -int tm_min; /\(** minutes (0 - 59) \(**/ -int tm_hour; /\(** hours (0 - 23) \(**/ -int tm_mday; /\(** day of month (1 - 31) \(**/ -int tm_mon; /\(** month of year (0 - 11) \(**/ -int tm_year; /\(** year \- 1900 \(**/ -int tm_wday; /\(** day of week (Sunday = 0) \(**/ -int tm_yday; /\(** day of year (0 - 365) \(**/ -int tm_isdst; /\(** is summer time in effect? \(**/ -char \(**tm_zone; /\(** abbreviation of timezone name \(**/ -long tm_gmtoff; /\(** offset from UTC in seconds \(**/ -.Ed -.Pp -The -field -.Fa tm_isdst -is non-zero if summer time is in effect. -.Pp -The field -.Fa tm_gmtoff -is the offset (in seconds) of the time represented from -.Tn UTC , -with positive -values indicating east of the Prime Meridian. -.Sh SEE ALSO -.Xr date 1 , -.Xr gettimeofday 2 , -.Xr getenv 3 , -.Xr time 3 , -.Xr tzset 3 , -.Xr tzfile 5 -.Sh STANDARDS -The -.Fn asctime , -.Fn ctime , -.Fn difftime , -.Fn gmtime , -.Fn localtime , -and -.Fn mktime -functions conform to -.St -isoC , -and conform to -.St -p1003.1-96 -provided the selected local timezone does not contain a leap-second table -(see -.Xr zic 8 ) . -.Pp -The -.Fn asctime_r , -.Fn ctime_r , -.Fn gmtime_r , -and -.Fn localtime_r -functions are expected to conform to -.St -p1003.1-96 -(again provided the selected local timezone does not contain a leap-second -table). -.Pp -The -.Fn timegm -function is not specified by any standard; its function cannot be -completely emulated using the standard functions described above. -.Sh HISTORY -This manual page is derived from -the time package contributed to Berkeley by -.An Arthur Olson -and which appeared in -.Bx 4.3 . -.Sh BUGS -Except for -.Fn difftime , -.Fn mktime , -and the -.Fn \&_r -variants of the other functions, -these functions leaves their result in an internal static object and return -a pointer to that object. -Subsequent calls to these -function will modify the same object. -.Pp -The C Standard provides no mechanism for a program to modify its current -local timezone setting, and the -.Tn POSIX Ns No \&-standard -method is not reentrant. -(However, thread-safe implementations are provided -in the -.Tn POSIX -threaded environment.) -.Pp -The -.Va tm_zone -field of a returned -.Vt tm -structure points to a static array of characters, -which will also be overwritten by any subsequent calls (as well as by -subsequent calls to -.Xr tzset 3 -and -.Xr tzsetwall 3 ) . -.Pp -Use of the external variable -.Fa tzname -is discouraged; the -.Fa tm_zone -entry in the tm structure is preferred. diff --git a/lib/libc/stdtime/difftime.c b/lib/libc/stdtime/difftime.c deleted file mode 100644 index d16f9a0..0000000 --- a/lib/libc/stdtime/difftime.c +++ /dev/null @@ -1,69 +0,0 @@ -/* -** This file is in the public domain, so clarified as of -** 1996-06-05 by Arthur David Olson. -*/ - -#include -#ifndef lint -#ifndef NOID -static char elsieid[] __unused = "@(#)difftime.c 8.1"; -#endif /* !defined NOID */ -#endif /* !defined lint */ -__FBSDID("$FreeBSD$"); - -/*LINTLIBRARY*/ - -#include "namespace.h" -#include "private.h" /* for time_t, TYPE_INTEGRAL, and TYPE_SIGNED */ -#include "un-namespace.h" - -double -difftime(time1, time0) -const time_t time1; -const time_t time0; -{ - /* - ** If (sizeof (double) > sizeof (time_t)) simply convert and subtract - ** (assuming that the larger type has more precision). - ** This is the common real-world case circa 2004. - */ - if (sizeof (double) > sizeof (time_t)) - return (double) time1 - (double) time0; - if (!TYPE_INTEGRAL(time_t)) { - /* - ** time_t is floating. - */ - return time1 - time0; - } - if (!TYPE_SIGNED(time_t)) { - /* - ** time_t is integral and unsigned. - ** The difference of two unsigned values can't overflow - ** if the minuend is greater than or equal to the subtrahend. - */ - if (time1 >= time0) - return time1 - time0; - else return -((double) (time0 - time1)); - } - /* - ** time_t is integral and signed. - ** Handle cases where both time1 and time0 have the same sign - ** (meaning that their difference cannot overflow). - */ - if ((time1 < 0) == (time0 < 0)) - return time1 - time0; - /* - ** time1 and time0 have opposite signs. - ** Punt if unsigned long is too narrow. - */ - if (sizeof (unsigned long) < sizeof (time_t)) - return (double) time1 - (double) time0; - /* - ** Stay calm...decent optimizers will eliminate the complexity below. - */ - if (time1 >= 0 /* && time0 < 0 */) - return (unsigned long) time1 + - (unsigned long) (-(time0 + 1)) + 1; - return -(double) ((unsigned long) time0 + - (unsigned long) (-(time1 + 1)) + 1); -} diff --git a/lib/libc/stdtime/localtime.c b/lib/libc/stdtime/localtime.c deleted file mode 100644 index bee916b..0000000 --- a/lib/libc/stdtime/localtime.c +++ /dev/null @@ -1,2249 +0,0 @@ -/* -** This file is in the public domain, so clarified as of -** 1996-06-05 by Arthur David Olson. -*/ - -#include -#ifndef lint -#ifndef NOID -static char elsieid[] __unused = "@(#)localtime.c 8.9"; -#endif /* !defined NOID */ -#endif /* !defined lint */ -__FBSDID("$FreeBSD$"); - -/* -** Leap second handling from Bradley White. -** POSIX-style TZ environment variable handling from Guy Harris. -*/ - -/*LINTLIBRARY*/ - -#include "namespace.h" -#include -#include -#include -#include -#include -#include "private.h" -#include "un-namespace.h" - -#include "tzfile.h" -#include "float.h" /* for FLT_MAX and DBL_MAX */ - -#ifndef TZ_ABBR_MAX_LEN -#define TZ_ABBR_MAX_LEN 16 -#endif /* !defined TZ_ABBR_MAX_LEN */ - -#ifndef TZ_ABBR_CHAR_SET -#define TZ_ABBR_CHAR_SET \ - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._" -#endif /* !defined TZ_ABBR_CHAR_SET */ - -#ifndef TZ_ABBR_ERR_CHAR -#define TZ_ABBR_ERR_CHAR '_' -#endif /* !defined TZ_ABBR_ERR_CHAR */ - -#include "libc_private.h" - -#define _MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x) -#define _MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x) - -#define _RWLOCK_RDLOCK(x) \ - do { \ - if (__isthreaded) _pthread_rwlock_rdlock(x); \ - } while (0) - -#define _RWLOCK_WRLOCK(x) \ - do { \ - if (__isthreaded) _pthread_rwlock_wrlock(x); \ - } while (0) - -#define _RWLOCK_UNLOCK(x) \ - do { \ - if (__isthreaded) _pthread_rwlock_unlock(x); \ - } while (0) - -/* -** SunOS 4.1.1 headers lack O_BINARY. -*/ - -#ifdef O_BINARY -#define OPEN_MODE (O_RDONLY | O_BINARY) -#endif /* defined O_BINARY */ -#ifndef O_BINARY -#define OPEN_MODE O_RDONLY -#endif /* !defined O_BINARY */ - -#ifndef WILDABBR -/* -** Someone might make incorrect use of a time zone abbreviation: -** 1. They might reference tzname[0] before calling tzset (explicitly -** or implicitly). -** 2. They might reference tzname[1] before calling tzset (explicitly -** or implicitly). -** 3. They might reference tzname[1] after setting to a time zone -** in which Daylight Saving Time is never observed. -** 4. They might reference tzname[0] after setting to a time zone -** in which Standard Time is never observed. -** 5. They might reference tm.TM_ZONE after calling offtime. -** What's best to do in the above cases is open to debate; -** for now, we just set things up so that in any of the five cases -** WILDABBR is used. Another possibility: initialize tzname[0] to the -** string "tzname[0] used before set", and similarly for the other cases. -** And another: initialize tzname[0] to "ERA", with an explanation in the -** manual page of what this "time zone abbreviation" means (doing this so -** that tzname[0] has the "normal" length of three characters). -*/ -#define WILDABBR " " -#endif /* !defined WILDABBR */ - -static char wildabbr[] = WILDABBR; - -/* - * In June 2004 it was decided UTC was a more appropriate default time - * zone than GMT. - */ - -static const char gmt[] = "UTC"; - -/* -** The DST rules to use if TZ has no rules and we can't load TZDEFRULES. -** We default to US rules as of 1999-08-17. -** POSIX 1003.1 section 8.1.1 says that the default DST rules are -** implementation dependent; for historical reasons, US rules are a -** common default. -*/ -#ifndef TZDEFRULESTRING -#define TZDEFRULESTRING ",M4.1.0,M10.5.0" -#endif /* !defined TZDEFDST */ - -struct ttinfo { /* time type information */ - long tt_gmtoff; /* UTC offset in seconds */ - int tt_isdst; /* used to set tm_isdst */ - int tt_abbrind; /* abbreviation list index */ - int tt_ttisstd; /* TRUE if transition is std time */ - int tt_ttisgmt; /* TRUE if transition is UTC */ -}; - -struct lsinfo { /* leap second information */ - time_t ls_trans; /* transition time */ - long ls_corr; /* correction to apply */ -}; - -#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) - -#ifdef TZNAME_MAX -#define MY_TZNAME_MAX TZNAME_MAX -#endif /* defined TZNAME_MAX */ -#ifndef TZNAME_MAX -#define MY_TZNAME_MAX 255 -#endif /* !defined TZNAME_MAX */ - -struct state { - int leapcnt; - int timecnt; - int typecnt; - int charcnt; - int goback; - int goahead; - time_t ats[TZ_MAX_TIMES]; - unsigned char types[TZ_MAX_TIMES]; - struct ttinfo ttis[TZ_MAX_TYPES]; - char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt), - (2 * (MY_TZNAME_MAX + 1)))]; - struct lsinfo lsis[TZ_MAX_LEAPS]; -}; - -struct rule { - int r_type; /* type of rule--see below */ - int r_day; /* day number of rule */ - int r_week; /* week number of rule */ - int r_mon; /* month number of rule */ - long r_time; /* transition time of rule */ -}; - -#define JULIAN_DAY 0 /* Jn - Julian day */ -#define DAY_OF_YEAR 1 /* n - day of year */ -#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ - -/* -** Prototypes for static functions. -*/ - -static long detzcode(const char * codep); -static time_t detzcode64(const char * codep); -static int differ_by_repeat(time_t t1, time_t t0); -static const char * getzname(const char * strp); -static const char * getqzname(const char * strp, const int delim); -static const char * getnum(const char * strp, int * nump, int min, - int max); -static const char * getsecs(const char * strp, long * secsp); -static const char * getoffset(const char * strp, long * offsetp); -static const char * getrule(const char * strp, struct rule * rulep); -static void gmtload(struct state * sp); -static struct tm * gmtsub(const time_t * timep, long offset, - struct tm * tmp); -static struct tm * localsub(const time_t * timep, long offset, - struct tm * tmp); -static int increment_overflow(int * number, int delta); -static int leaps_thru_end_of(int y); -static int long_increment_overflow(long * number, int delta); -static int long_normalize_overflow(long * tensptr, - int * unitsptr, int base); -static int normalize_overflow(int * tensptr, int * unitsptr, - int base); -static void settzname(void); -static time_t time1(struct tm * tmp, - struct tm * (*funcp)(const time_t *, - long, struct tm *), - long offset); -static time_t time2(struct tm *tmp, - struct tm * (*funcp)(const time_t *, - long, struct tm*), - long offset, int * okayp); -static time_t time2sub(struct tm *tmp, - struct tm * (*funcp)(const time_t *, - long, struct tm*), - long offset, int * okayp, int do_norm_secs); -static struct tm * timesub(const time_t * timep, long offset, - const struct state * sp, struct tm * tmp); -static int tmcomp(const struct tm * atmp, - const struct tm * btmp); -static time_t transtime(time_t janfirst, int year, - const struct rule * rulep, long offset); -static int typesequiv(const struct state * sp, int a, int b); -static int tzload(const char * name, struct state * sp, - int doextend); -static int tzparse(const char * name, struct state * sp, - int lastditch); - -#ifdef ALL_STATE -static struct state * lclptr; -static struct state * gmtptr; -#endif /* defined ALL_STATE */ - -#ifndef ALL_STATE -static struct state lclmem; -static struct state gmtmem; -#define lclptr (&lclmem) -#define gmtptr (&gmtmem) -#endif /* State Farm */ - -#ifndef TZ_STRLEN_MAX -#define TZ_STRLEN_MAX 255 -#endif /* !defined TZ_STRLEN_MAX */ - -static char lcl_TZname[TZ_STRLEN_MAX + 1]; -static int lcl_is_set; -static pthread_once_t gmt_once = PTHREAD_ONCE_INIT; -static pthread_rwlock_t lcl_rwlock = PTHREAD_RWLOCK_INITIALIZER; -static pthread_once_t gmtime_once = PTHREAD_ONCE_INIT; -static pthread_key_t gmtime_key; -static int gmtime_key_error; -static pthread_once_t localtime_once = PTHREAD_ONCE_INIT; -static pthread_key_t localtime_key; -static int localtime_key_error; - -char * tzname[2] = { - wildabbr, - wildabbr -}; - -/* -** Section 4.12.3 of X3.159-1989 requires that -** Except for the strftime function, these functions [asctime, -** ctime, gmtime, localtime] return values in one of two static -** objects: a broken-down time structure and an array of char. -** Thanks to Paul Eggert for noting this. -*/ - -static struct tm tm; - -#ifdef USG_COMPAT -time_t timezone = 0; -int daylight = 0; -#endif /* defined USG_COMPAT */ - -#ifdef ALTZONE -time_t altzone = 0; -#endif /* defined ALTZONE */ - -static long -detzcode(codep) -const char * const codep; -{ - long result; - int i; - - result = (codep[0] & 0x80) ? ~0L : 0; - for (i = 0; i < 4; ++i) - result = (result << 8) | (codep[i] & 0xff); - return result; -} - -static time_t -detzcode64(codep) -const char * const codep; -{ - register time_t result; - register int i; - - result = (codep[0] & 0x80) ? (~(int_fast64_t) 0) : 0; - for (i = 0; i < 8; ++i) - result = result * 256 + (codep[i] & 0xff); - return result; -} - -static void -settzname(void) -{ - struct state * sp = lclptr; - int i; - - tzname[0] = wildabbr; - tzname[1] = wildabbr; -#ifdef USG_COMPAT - daylight = 0; - timezone = 0; -#endif /* defined USG_COMPAT */ -#ifdef ALTZONE - altzone = 0; -#endif /* defined ALTZONE */ -#ifdef ALL_STATE - if (sp == NULL) { - tzname[0] = tzname[1] = gmt; - return; - } -#endif /* defined ALL_STATE */ - for (i = 0; i < sp->typecnt; ++i) { - const struct ttinfo * const ttisp = &sp->ttis[i]; - - tzname[ttisp->tt_isdst] = - &sp->chars[ttisp->tt_abbrind]; -#ifdef USG_COMPAT - if (ttisp->tt_isdst) - daylight = 1; - if (i == 0 || !ttisp->tt_isdst) - timezone = -(ttisp->tt_gmtoff); -#endif /* defined USG_COMPAT */ -#ifdef ALTZONE - if (i == 0 || ttisp->tt_isdst) - altzone = -(ttisp->tt_gmtoff); -#endif /* defined ALTZONE */ - } - /* - ** And to get the latest zone names into tzname. . . - */ - for (i = 0; i < sp->timecnt; ++i) { - const struct ttinfo * const ttisp = - &sp->ttis[ - sp->types[i]]; - - tzname[ttisp->tt_isdst] = - &sp->chars[ttisp->tt_abbrind]; - } - /* - ** Finally, scrub the abbreviations. - ** First, replace bogus characters. - */ - for (i = 0; i < sp->charcnt; ++i) - if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL) - sp->chars[i] = TZ_ABBR_ERR_CHAR; - /* - ** Second, truncate long abbreviations. - */ - for (i = 0; i < sp->typecnt; ++i) { - register const struct ttinfo * const ttisp = &sp->ttis[i]; - register char * cp = &sp->chars[ttisp->tt_abbrind]; - - if (strlen(cp) > TZ_ABBR_MAX_LEN && - strcmp(cp, GRANDPARENTED) != 0) - *(cp + TZ_ABBR_MAX_LEN) = '\0'; - } -} - -static int -differ_by_repeat(t1, t0) -const time_t t1; -const time_t t0; -{ - int_fast64_t _t0 = t0; - int_fast64_t _t1 = t1; - - if (TYPE_INTEGRAL(time_t) && - TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS) - return 0; - //turn ((int_fast64_t)(t1 - t0) == SECSPERREPEAT); - return _t1 - _t0 == SECSPERREPEAT; -} - -static int -tzload(name, sp, doextend) -const char * name; -struct state * const sp; -register const int doextend; -{ - const char * p; - int i; - int fid; - int stored; - int nread; - union { - struct tzhead tzhead; - char buf[2 * sizeof(struct tzhead) + - 2 * sizeof *sp + - 4 * TZ_MAX_TIMES]; - } u; - - /* XXX The following is from OpenBSD, and I'm not sure it is correct */ - if (name != NULL && issetugid() != 0) - if ((name[0] == ':' && name[1] == '/') || - name[0] == '/' || strchr(name, '.')) - name = NULL; - if (name == NULL && (name = TZDEFAULT) == NULL) - return -1; - { - int doaccess; - struct stat stab; - /* - ** Section 4.9.1 of the C standard says that - ** "FILENAME_MAX expands to an integral constant expression - ** that is the size needed for an array of char large enough - ** to hold the longest file name string that the implementation - ** guarantees can be opened." - */ - char fullname[FILENAME_MAX + 1]; - - if (name[0] == ':') - ++name; - doaccess = name[0] == '/'; - if (!doaccess) { - if ((p = TZDIR) == NULL) - return -1; - if ((strlen(p) + 1 + strlen(name) + 1) >= sizeof fullname) - return -1; - (void) strcpy(fullname, p); - (void) strcat(fullname, "/"); - (void) strcat(fullname, name); - /* - ** Set doaccess if '.' (as in "../") shows up in name. - */ - if (strchr(name, '.') != NULL) - doaccess = TRUE; - name = fullname; - } - if (doaccess && access(name, R_OK) != 0) - return -1; - if ((fid = _open(name, OPEN_MODE)) == -1) - return -1; - if ((_fstat(fid, &stab) < 0) || !S_ISREG(stab.st_mode)) { - _close(fid); - return -1; - } - } - nread = _read(fid, u.buf, sizeof u.buf); - if (_close(fid) < 0 || nread <= 0) - return -1; - for (stored = 4; stored <= 8; stored *= 2) { - int ttisstdcnt; - int ttisgmtcnt; - - ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt); - ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt); - sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt); - sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt); - sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt); - sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt); - p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt; - if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS || - sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || - sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || - sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || - (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) || - (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0)) - return -1; - if (nread - (p - u.buf) < - sp->timecnt * stored + /* ats */ - sp->timecnt + /* types */ - sp->typecnt * 6 + /* ttinfos */ - sp->charcnt + /* chars */ - sp->leapcnt * (stored + 4) + /* lsinfos */ - ttisstdcnt + /* ttisstds */ - ttisgmtcnt) /* ttisgmts */ - return -1; - for (i = 0; i < sp->timecnt; ++i) { - sp->ats[i] = (stored == 4) ? - detzcode(p) : detzcode64(p); - p += stored; - } - for (i = 0; i < sp->timecnt; ++i) { - sp->types[i] = (unsigned char) *p++; - if (sp->types[i] >= sp->typecnt) - return -1; - } - for (i = 0; i < sp->typecnt; ++i) { - struct ttinfo * ttisp; - - ttisp = &sp->ttis[i]; - ttisp->tt_gmtoff = detzcode(p); - p += 4; - ttisp->tt_isdst = (unsigned char) *p++; - if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) - return -1; - ttisp->tt_abbrind = (unsigned char) *p++; - if (ttisp->tt_abbrind < 0 || - ttisp->tt_abbrind > sp->charcnt) - return -1; - } - for (i = 0; i < sp->charcnt; ++i) - sp->chars[i] = *p++; - sp->chars[i] = '\0'; /* ensure '\0' at end */ - for (i = 0; i < sp->leapcnt; ++i) { - struct lsinfo * lsisp; - - lsisp = &sp->lsis[i]; - lsisp->ls_trans = (stored == 4) ? - detzcode(p) : detzcode64(p); - p += stored; - lsisp->ls_corr = detzcode(p); - p += 4; - } - for (i = 0; i < sp->typecnt; ++i) { - struct ttinfo * ttisp; - - ttisp = &sp->ttis[i]; - if (ttisstdcnt == 0) - ttisp->tt_ttisstd = FALSE; - else { - ttisp->tt_ttisstd = *p++; - if (ttisp->tt_ttisstd != TRUE && - ttisp->tt_ttisstd != FALSE) - return -1; - } - } - for (i = 0; i < sp->typecnt; ++i) { - struct ttinfo * ttisp; - - ttisp = &sp->ttis[i]; - if (ttisgmtcnt == 0) - ttisp->tt_ttisgmt = FALSE; - else { - ttisp->tt_ttisgmt = *p++; - if (ttisp->tt_ttisgmt != TRUE && - ttisp->tt_ttisgmt != FALSE) - return -1; - } - } - /* - ** Out-of-sort ats should mean we're running on a - ** signed time_t system but using a data file with - ** unsigned values (or vice versa). - */ - for (i = 0; i < sp->timecnt - 2; ++i) - if (sp->ats[i] > sp->ats[i + 1]) { - ++i; - if (TYPE_SIGNED(time_t)) { - /* - ** Ignore the end (easy). - */ - sp->timecnt = i; - } else { - /* - ** Ignore the beginning (harder). - */ - register int j; - - for (j = 0; j + i < sp->timecnt; ++j) { - sp->ats[j] = sp->ats[j + i]; - sp->types[j] = sp->types[j + i]; - } - sp->timecnt = j; - } - break; - } - /* - ** If this is an old file, we're done. - */ - if (u.tzhead.tzh_version[0] == '\0') - break; - nread -= p - u.buf; - for (i = 0; i < nread; ++i) - u.buf[i] = p[i]; - /* - ** If this is a narrow integer time_t system, we're done. - */ - if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t)) - break; - } - if (doextend && nread > 2 && - u.buf[0] == '\n' && u.buf[nread - 1] == '\n' && - sp->typecnt + 2 <= TZ_MAX_TYPES) { - struct state ts; - register int result; - - u.buf[nread - 1] = '\0'; - result = tzparse(&u.buf[1], &ts, FALSE); - if (result == 0 && ts.typecnt == 2 && - sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) { - for (i = 0; i < 2; ++i) - ts.ttis[i].tt_abbrind += - sp->charcnt; - for (i = 0; i < ts.charcnt; ++i) - sp->chars[sp->charcnt++] = - ts.chars[i]; - i = 0; - while (i < ts.timecnt && - ts.ats[i] <= - sp->ats[sp->timecnt - 1]) - ++i; - while (i < ts.timecnt && - sp->timecnt < TZ_MAX_TIMES) { - sp->ats[sp->timecnt] = - ts.ats[i]; - sp->types[sp->timecnt] = - sp->typecnt + - ts.types[i]; - ++sp->timecnt; - ++i; - } - sp->ttis[sp->typecnt++] = ts.ttis[0]; - sp->ttis[sp->typecnt++] = ts.ttis[1]; - } - } - sp->goback = sp->goahead = FALSE; - if (sp->timecnt > 1) { - for (i = 1; i < sp->timecnt; ++i) - if (typesequiv(sp, sp->types[i], sp->types[0]) && - differ_by_repeat(sp->ats[i], sp->ats[0])) { - sp->goback = TRUE; - break; - } - for (i = sp->timecnt - 2; i >= 0; --i) - if (typesequiv(sp, sp->types[sp->timecnt - 1], - sp->types[i]) && - differ_by_repeat(sp->ats[sp->timecnt - 1], - sp->ats[i])) { - sp->goahead = TRUE; - break; - } - } - return 0; -} - -static int -typesequiv(sp, a, b) -const struct state * const sp; -const int a; -const int b; -{ - register int result; - - if (sp == NULL || - a < 0 || a >= sp->typecnt || - b < 0 || b >= sp->typecnt) - result = FALSE; - else { - register const struct ttinfo * ap = &sp->ttis[a]; - register const struct ttinfo * bp = &sp->ttis[b]; - result = ap->tt_gmtoff == bp->tt_gmtoff && - ap->tt_isdst == bp->tt_isdst && - ap->tt_ttisstd == bp->tt_ttisstd && - ap->tt_ttisgmt == bp->tt_ttisgmt && - strcmp(&sp->chars[ap->tt_abbrind], - &sp->chars[bp->tt_abbrind]) == 0; - } - return result; -} - -static const int mon_lengths[2][MONSPERYEAR] = { - { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, - { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } -}; - -static const int year_lengths[2] = { - DAYSPERNYEAR, DAYSPERLYEAR -}; - -/* -** Given a pointer into a time zone string, scan until a character that is not -** a valid character in a zone name is found. Return a pointer to that -** character. -*/ - -static const char * -getzname(strp) -const char * strp; -{ - char c; - - while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && - c != '+') - ++strp; - return strp; -} - -/* -** Given a pointer into an extended time zone string, scan until the ending -** delimiter of the zone name is located. Return a pointer to the delimiter. -** -** As with getzname above, the legal character set is actually quite -** restricted, with other characters producing undefined results. -** We don't do any checking here; checking is done later in common-case code. -*/ - -static const char * -getqzname(register const char *strp, const int delim) -{ - register int c; - - while ((c = *strp) != '\0' && c != delim) - ++strp; - return strp; -} - -/* -** Given a pointer into a time zone string, extract a number from that string. -** Check that the number is within a specified range; if it is not, return -** NULL. -** Otherwise, return a pointer to the first character not part of the number. -*/ - -static const char * -getnum(strp, nump, min, max) -const char * strp; -int * const nump; -const int min; -const int max; -{ - char c; - int num; - - if (strp == NULL || !is_digit(c = *strp)) - return NULL; - num = 0; - do { - num = num * 10 + (c - '0'); - if (num > max) - return NULL; /* illegal value */ - c = *++strp; - } while (is_digit(c)); - if (num < min) - return NULL; /* illegal value */ - *nump = num; - return strp; -} - -/* -** Given a pointer into a time zone string, extract a number of seconds, -** in hh[:mm[:ss]] form, from the string. -** If any error occurs, return NULL. -** Otherwise, return a pointer to the first character not part of the number -** of seconds. -*/ - -static const char * -getsecs(strp, secsp) -const char * strp; -long * const secsp; -{ - int num; - - /* - ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like - ** "M10.4.6/26", which does not conform to Posix, - ** but which specifies the equivalent of - ** ``02:00 on the first Sunday on or after 23 Oct''. - */ - strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1); - if (strp == NULL) - return NULL; - *secsp = num * (long) SECSPERHOUR; - if (*strp == ':') { - ++strp; - strp = getnum(strp, &num, 0, MINSPERHOUR - 1); - if (strp == NULL) - return NULL; - *secsp += num * SECSPERMIN; - if (*strp == ':') { - ++strp; - /* `SECSPERMIN' allows for leap seconds. */ - strp = getnum(strp, &num, 0, SECSPERMIN); - if (strp == NULL) - return NULL; - *secsp += num; - } - } - return strp; -} - -/* -** Given a pointer into a time zone string, extract an offset, in -** [+-]hh[:mm[:ss]] form, from the string. -** If any error occurs, return NULL. -** Otherwise, return a pointer to the first character not part of the time. -*/ - -static const char * -getoffset(strp, offsetp) -const char * strp; -long * const offsetp; -{ - int neg = 0; - - if (*strp == '-') { - neg = 1; - ++strp; - } else if (*strp == '+') - ++strp; - strp = getsecs(strp, offsetp); - if (strp == NULL) - return NULL; /* illegal time */ - if (neg) - *offsetp = -*offsetp; - return strp; -} - -/* -** Given a pointer into a time zone string, extract a rule in the form -** date[/time]. See POSIX section 8 for the format of "date" and "time". -** If a valid rule is not found, return NULL. -** Otherwise, return a pointer to the first character not part of the rule. -*/ - -static const char * -getrule(strp, rulep) -const char * strp; -struct rule * const rulep; -{ - if (*strp == 'J') { - /* - ** Julian day. - */ - rulep->r_type = JULIAN_DAY; - ++strp; - strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); - } else if (*strp == 'M') { - /* - ** Month, week, day. - */ - rulep->r_type = MONTH_NTH_DAY_OF_WEEK; - ++strp; - strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); - if (strp == NULL) - return NULL; - if (*strp++ != '.') - return NULL; - strp = getnum(strp, &rulep->r_week, 1, 5); - if (strp == NULL) - return NULL; - if (*strp++ != '.') - return NULL; - strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); - } else if (is_digit(*strp)) { - /* - ** Day of year. - */ - rulep->r_type = DAY_OF_YEAR; - strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); - } else return NULL; /* invalid format */ - if (strp == NULL) - return NULL; - if (*strp == '/') { - /* - ** Time specified. - */ - ++strp; - strp = getsecs(strp, &rulep->r_time); - } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ - return strp; -} - -/* -** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the -** year, a rule, and the offset from UTC at the time that rule takes effect, -** calculate the Epoch-relative time that rule takes effect. -*/ - -static time_t -transtime(janfirst, year, rulep, offset) -const time_t janfirst; -const int year; -const struct rule * const rulep; -const long offset; -{ - int leapyear; - time_t value; - int i; - int d, m1, yy0, yy1, yy2, dow; - - INITIALIZE(value); - leapyear = isleap(year); - switch (rulep->r_type) { - - case JULIAN_DAY: - /* - ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap - ** years. - ** In non-leap years, or if the day number is 59 or less, just - ** add SECSPERDAY times the day number-1 to the time of - ** January 1, midnight, to get the day. - */ - value = janfirst + (rulep->r_day - 1) * SECSPERDAY; - if (leapyear && rulep->r_day >= 60) - value += SECSPERDAY; - break; - - case DAY_OF_YEAR: - /* - ** n - day of year. - ** Just add SECSPERDAY times the day number to the time of - ** January 1, midnight, to get the day. - */ - value = janfirst + rulep->r_day * SECSPERDAY; - break; - - case MONTH_NTH_DAY_OF_WEEK: - /* - ** Mm.n.d - nth "dth day" of month m. - */ - value = janfirst; - for (i = 0; i < rulep->r_mon - 1; ++i) - value += mon_lengths[leapyear][i] * SECSPERDAY; - - /* - ** Use Zeller's Congruence to get day-of-week of first day of - ** month. - */ - m1 = (rulep->r_mon + 9) % 12 + 1; - yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; - yy1 = yy0 / 100; - yy2 = yy0 % 100; - dow = ((26 * m1 - 2) / 10 + - 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; - if (dow < 0) - dow += DAYSPERWEEK; - - /* - ** "dow" is the day-of-week of the first day of the month. Get - ** the day-of-month (zero-origin) of the first "dow" day of the - ** month. - */ - d = rulep->r_day - dow; - if (d < 0) - d += DAYSPERWEEK; - for (i = 1; i < rulep->r_week; ++i) { - if (d + DAYSPERWEEK >= - mon_lengths[leapyear][rulep->r_mon - 1]) - break; - d += DAYSPERWEEK; - } - - /* - ** "d" is the day-of-month (zero-origin) of the day we want. - */ - value += d * SECSPERDAY; - break; - } - - /* - ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in - ** question. To get the Epoch-relative time of the specified local - ** time on that day, add the transition time and the current offset - ** from UTC. - */ - return value + rulep->r_time + offset; -} - -/* -** Given a POSIX section 8-style TZ string, fill in the rule tables as -** appropriate. -*/ - -static int -tzparse(name, sp, lastditch) -const char * name; -struct state * const sp; -const int lastditch; -{ - const char * stdname; - const char * dstname; - size_t stdlen; - size_t dstlen; - long stdoffset; - long dstoffset; - time_t * atp; - unsigned char * typep; - char * cp; - int load_result; - - INITIALIZE(dstname); - stdname = name; - if (lastditch) { - stdlen = strlen(name); /* length of standard zone name */ - name += stdlen; - if (stdlen >= sizeof sp->chars) - stdlen = (sizeof sp->chars) - 1; - stdoffset = 0; - } else { - if (*name == '<') { - name++; - stdname = name; - name = getqzname(name, '>'); - if (*name != '>') - return (-1); - stdlen = name - stdname; - name++; - } else { - name = getzname(name); - stdlen = name - stdname; - } - if (*name == '\0') - return -1; /* was "stdoffset = 0;" */ - else { - name = getoffset(name, &stdoffset); - if (name == NULL) - return -1; - } - } - load_result = tzload(TZDEFRULES, sp, FALSE); - if (load_result != 0) - sp->leapcnt = 0; /* so, we're off a little */ - if (*name != '\0') { - if (*name == '<') { - dstname = ++name; - name = getqzname(name, '>'); - if (*name != '>') - return -1; - dstlen = name - dstname; - name++; - } else { - dstname = name; - name = getzname(name); - dstlen = name - dstname; /* length of DST zone name */ - } - if (*name != '\0' && *name != ',' && *name != ';') { - name = getoffset(name, &dstoffset); - if (name == NULL) - return -1; - } else dstoffset = stdoffset - SECSPERHOUR; - if (*name == '\0' && load_result != 0) - name = TZDEFRULESTRING; - if (*name == ',' || *name == ';') { - struct rule start; - struct rule end; - int year; - time_t janfirst; - time_t starttime; - time_t endtime; - - ++name; - if ((name = getrule(name, &start)) == NULL) - return -1; - if (*name++ != ',') - return -1; - if ((name = getrule(name, &end)) == NULL) - return -1; - if (*name != '\0') - return -1; - sp->typecnt = 2; /* standard time and DST */ - /* - ** Two transitions per year, from EPOCH_YEAR forward. - */ - sp->ttis[0].tt_gmtoff = -dstoffset; - sp->ttis[0].tt_isdst = 1; - sp->ttis[0].tt_abbrind = stdlen + 1; - sp->ttis[1].tt_gmtoff = -stdoffset; - sp->ttis[1].tt_isdst = 0; - sp->ttis[1].tt_abbrind = 0; - atp = sp->ats; - typep = sp->types; - janfirst = 0; - sp->timecnt = 0; - for (year = EPOCH_YEAR; - sp->timecnt + 2 <= TZ_MAX_TIMES; - ++year) { - time_t newfirst; - - starttime = transtime(janfirst, year, &start, - stdoffset); - endtime = transtime(janfirst, year, &end, - dstoffset); - if (starttime > endtime) { - *atp++ = endtime; - *typep++ = 1; /* DST ends */ - *atp++ = starttime; - *typep++ = 0; /* DST begins */ - } else { - *atp++ = starttime; - *typep++ = 0; /* DST begins */ - *atp++ = endtime; - *typep++ = 1; /* DST ends */ - } - sp->timecnt += 2; - newfirst = janfirst; - newfirst += year_lengths[isleap(year)] * - SECSPERDAY; - if (newfirst <= janfirst) - break; - janfirst = newfirst; - } - } else { - long theirstdoffset; - long theirdstoffset; - long theiroffset; - int isdst; - int i; - int j; - - if (*name != '\0') - return -1; - /* - ** Initial values of theirstdoffset and theirdstoffset. - */ - theirstdoffset = 0; - for (i = 0; i < sp->timecnt; ++i) { - j = sp->types[i]; - if (!sp->ttis[j].tt_isdst) { - theirstdoffset = - -sp->ttis[j].tt_gmtoff; - break; - } - } - theirdstoffset = 0; - for (i = 0; i < sp->timecnt; ++i) { - j = sp->types[i]; - if (sp->ttis[j].tt_isdst) { - theirdstoffset = - -sp->ttis[j].tt_gmtoff; - break; - } - } - /* - ** Initially we're assumed to be in standard time. - */ - isdst = FALSE; - theiroffset = theirstdoffset; - /* - ** Now juggle transition times and types - ** tracking offsets as you do. - */ - for (i = 0; i < sp->timecnt; ++i) { - j = sp->types[i]; - sp->types[i] = sp->ttis[j].tt_isdst; - if (sp->ttis[j].tt_ttisgmt) { - /* No adjustment to transition time */ - } else { - /* - ** If summer time is in effect, and the - ** transition time was not specified as - ** standard time, add the summer time - ** offset to the transition time; - ** otherwise, add the standard time - ** offset to the transition time. - */ - /* - ** Transitions from DST to DDST - ** will effectively disappear since - ** POSIX provides for only one DST - ** offset. - */ - if (isdst && !sp->ttis[j].tt_ttisstd) { - sp->ats[i] += dstoffset - - theirdstoffset; - } else { - sp->ats[i] += stdoffset - - theirstdoffset; - } - } - theiroffset = -sp->ttis[j].tt_gmtoff; - if (sp->ttis[j].tt_isdst) - theirdstoffset = theiroffset; - else theirstdoffset = theiroffset; - } - /* - ** Finally, fill in ttis. - ** ttisstd and ttisgmt need not be handled. - */ - sp->ttis[0].tt_gmtoff = -stdoffset; - sp->ttis[0].tt_isdst = FALSE; - sp->ttis[0].tt_abbrind = 0; - sp->ttis[1].tt_gmtoff = -dstoffset; - sp->ttis[1].tt_isdst = TRUE; - sp->ttis[1].tt_abbrind = stdlen + 1; - sp->typecnt = 2; - } - } else { - dstlen = 0; - sp->typecnt = 1; /* only standard time */ - sp->timecnt = 0; - sp->ttis[0].tt_gmtoff = -stdoffset; - sp->ttis[0].tt_isdst = 0; - sp->ttis[0].tt_abbrind = 0; - } - sp->charcnt = stdlen + 1; - if (dstlen != 0) - sp->charcnt += dstlen + 1; - if ((size_t) sp->charcnt > sizeof sp->chars) - return -1; - cp = sp->chars; - (void) strncpy(cp, stdname, stdlen); - cp += stdlen; - *cp++ = '\0'; - if (dstlen != 0) { - (void) strncpy(cp, dstname, dstlen); - *(cp + dstlen) = '\0'; - } - return 0; -} - -static void -gmtload(sp) -struct state * const sp; -{ - if (tzload(gmt, sp, TRUE) != 0) - (void) tzparse(gmt, sp, TRUE); -} - -static void -tzsetwall_basic(int rdlocked) -{ - if (!rdlocked) - _RWLOCK_RDLOCK(&lcl_rwlock); - if (lcl_is_set < 0) { - if (!rdlocked) - _RWLOCK_UNLOCK(&lcl_rwlock); - return; - } - _RWLOCK_UNLOCK(&lcl_rwlock); - - _RWLOCK_WRLOCK(&lcl_rwlock); - lcl_is_set = -1; - -#ifdef ALL_STATE - if (lclptr == NULL) { - lclptr = (struct state *) malloc(sizeof *lclptr); - if (lclptr == NULL) { - settzname(); /* all we can do */ - _RWLOCK_UNLOCK(&lcl_rwlock); - if (rdlocked) - _RWLOCK_RDLOCK(&lcl_rwlock); - return; - } - } -#endif /* defined ALL_STATE */ - if (tzload((char *) NULL, lclptr, TRUE) != 0) - gmtload(lclptr); - settzname(); - _RWLOCK_UNLOCK(&lcl_rwlock); - - if (rdlocked) - _RWLOCK_RDLOCK(&lcl_rwlock); -} - -void -tzsetwall(void) -{ - tzsetwall_basic(0); -} - -static void -tzset_basic(int rdlocked) -{ - const char * name; - - name = getenv("TZ"); - if (name == NULL) { - tzsetwall_basic(rdlocked); - return; - } - - if (!rdlocked) - _RWLOCK_RDLOCK(&lcl_rwlock); - if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) { - if (!rdlocked) - _RWLOCK_UNLOCK(&lcl_rwlock); - return; - } - _RWLOCK_UNLOCK(&lcl_rwlock); - - _RWLOCK_WRLOCK(&lcl_rwlock); - lcl_is_set = strlen(name) < sizeof lcl_TZname; - if (lcl_is_set) - (void) strcpy(lcl_TZname, name); - -#ifdef ALL_STATE - if (lclptr == NULL) { - lclptr = (struct state *) malloc(sizeof *lclptr); - if (lclptr == NULL) { - settzname(); /* all we can do */ - _RWLOCK_UNLOCK(&lcl_rwlock); - if (rdlocked) - _RWLOCK_RDLOCK(&lcl_rwlock); - return; - } - } -#endif /* defined ALL_STATE */ - if (*name == '\0') { - /* - ** User wants it fast rather than right. - */ - lclptr->leapcnt = 0; /* so, we're off a little */ - lclptr->timecnt = 0; - lclptr->typecnt = 0; - lclptr->ttis[0].tt_isdst = 0; - lclptr->ttis[0].tt_gmtoff = 0; - lclptr->ttis[0].tt_abbrind = 0; - (void) strcpy(lclptr->chars, gmt); - } else if (tzload(name, lclptr, TRUE) != 0) - if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) - (void) gmtload(lclptr); - settzname(); - _RWLOCK_UNLOCK(&lcl_rwlock); - - if (rdlocked) - _RWLOCK_RDLOCK(&lcl_rwlock); -} - -void -tzset(void) -{ - tzset_basic(0); -} - -/* -** The easy way to behave "as if no library function calls" localtime -** is to not call it--so we drop its guts into "localsub", which can be -** freely called. (And no, the PANS doesn't require the above behavior-- -** but it *is* desirable.) -** -** The unused offset argument is for the benefit of mktime variants. -*/ - -/*ARGSUSED*/ -static struct tm * -localsub(timep, offset, tmp) -const time_t * const timep; -const long offset; -struct tm * const tmp; -{ - struct state * sp; - const struct ttinfo * ttisp; - int i; - struct tm * result; - const time_t t = *timep; - - sp = lclptr; -#ifdef ALL_STATE - if (sp == NULL) - return gmtsub(timep, offset, tmp); -#endif /* defined ALL_STATE */ - if ((sp->goback && t < sp->ats[0]) || - (sp->goahead && t > sp->ats[sp->timecnt - 1])) { - time_t newt = t; - register time_t seconds; - register time_t tcycles; - register int_fast64_t icycles; - - if (t < sp->ats[0]) - seconds = sp->ats[0] - t; - else seconds = t - sp->ats[sp->timecnt - 1]; - --seconds; - tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR; - ++tcycles; - icycles = tcycles; - if (tcycles - icycles >= 1 || icycles - tcycles >= 1) - return NULL; - seconds = icycles; - seconds *= YEARSPERREPEAT; - seconds *= AVGSECSPERYEAR; - if (t < sp->ats[0]) - newt += seconds; - else newt -= seconds; - if (newt < sp->ats[0] || - newt > sp->ats[sp->timecnt - 1]) - return NULL; /* "cannot happen" */ - result = localsub(&newt, offset, tmp); - if (result == tmp) { - register time_t newy; - - newy = tmp->tm_year; - if (t < sp->ats[0]) - newy -= icycles * YEARSPERREPEAT; - else newy += icycles * YEARSPERREPEAT; - tmp->tm_year = newy; - if (tmp->tm_year != newy) - return NULL; - } - return result; - } - if (sp->timecnt == 0 || t < sp->ats[0]) { - i = 0; - while (sp->ttis[i].tt_isdst) - if (++i >= sp->typecnt) { - i = 0; - break; - } - } else { - register int lo = 1; - register int hi = sp->timecnt; - - while (lo < hi) { - register int mid = (lo + hi) >> 1; - - if (t < sp->ats[mid]) - hi = mid; - else lo = mid + 1; - } - i = (int) sp->types[lo - 1]; - } - ttisp = &sp->ttis[i]; - /* - ** To get (wrong) behavior that's compatible with System V Release 2.0 - ** you'd replace the statement below with - ** t += ttisp->tt_gmtoff; - ** timesub(&t, 0L, sp, tmp); - */ - result = timesub(&t, ttisp->tt_gmtoff, sp, tmp); - tmp->tm_isdst = ttisp->tt_isdst; - tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind]; -#ifdef TM_ZONE - tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind]; -#endif /* defined TM_ZONE */ - return result; -} - -static void -localtime_key_init(void) -{ - - localtime_key_error = _pthread_key_create(&localtime_key, free); -} - -struct tm * -localtime(timep) -const time_t * const timep; -{ - struct tm *p_tm; - - if (__isthreaded != 0) { - _pthread_once(&localtime_once, localtime_key_init); - if (localtime_key_error != 0) { - errno = localtime_key_error; - return(NULL); - } - p_tm = _pthread_getspecific(localtime_key); - if (p_tm == NULL) { - if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) - == NULL) - return(NULL); - _pthread_setspecific(localtime_key, p_tm); - } - _RWLOCK_RDLOCK(&lcl_rwlock); - tzset_basic(1); - localsub(timep, 0L, p_tm); - _RWLOCK_UNLOCK(&lcl_rwlock); - return(p_tm); - } else { - tzset_basic(0); - localsub(timep, 0L, &tm); - return(&tm); - } -} - -/* -** Re-entrant version of localtime. -*/ - -struct tm * -localtime_r(timep, tmp) -const time_t * const timep; -struct tm * tmp; -{ - _RWLOCK_RDLOCK(&lcl_rwlock); - tzset_basic(1); - localsub(timep, 0L, tmp); - _RWLOCK_UNLOCK(&lcl_rwlock); - return tmp; -} - -static void -gmt_init(void) -{ - -#ifdef ALL_STATE - gmtptr = (struct state *) malloc(sizeof *gmtptr); - if (gmtptr != NULL) -#endif /* defined ALL_STATE */ - gmtload(gmtptr); -} - -/* -** gmtsub is to gmtime as localsub is to localtime. -*/ - -static struct tm * -gmtsub(timep, offset, tmp) -const time_t * const timep; -const long offset; -struct tm * const tmp; -{ - register struct tm * result; - - _once(&gmt_once, gmt_init); - result = timesub(timep, offset, gmtptr, tmp); -#ifdef TM_ZONE - /* - ** Could get fancy here and deliver something such as - ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero, - ** but this is no time for a treasure hunt. - */ - if (offset != 0) - tmp->TM_ZONE = wildabbr; - else { -#ifdef ALL_STATE - if (gmtptr == NULL) - tmp->TM_ZONE = gmt; - else tmp->TM_ZONE = gmtptr->chars; -#endif /* defined ALL_STATE */ -#ifndef ALL_STATE - tmp->TM_ZONE = gmtptr->chars; -#endif /* State Farm */ - } -#endif /* defined TM_ZONE */ - return result; -} - -static void -gmtime_key_init(void) -{ - - gmtime_key_error = _pthread_key_create(&gmtime_key, free); -} - -struct tm * -gmtime(timep) -const time_t * const timep; -{ - struct tm *p_tm; - - if (__isthreaded != 0) { - _pthread_once(&gmtime_once, gmtime_key_init); - if (gmtime_key_error != 0) { - errno = gmtime_key_error; - return(NULL); - } - /* - * Changed to follow POSIX.1 threads standard, which - * is what BSD currently has. - */ - if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) { - if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) - == NULL) { - return(NULL); - } - _pthread_setspecific(gmtime_key, p_tm); - } - gmtsub(timep, 0L, p_tm); - return(p_tm); - } - else { - gmtsub(timep, 0L, &tm); - return(&tm); - } -} - -/* -* Re-entrant version of gmtime. -*/ - -struct tm * -gmtime_r(timep, tmp) -const time_t * const timep; -struct tm * tmp; -{ - return gmtsub(timep, 0L, tmp); -} - -#ifdef STD_INSPIRED - -struct tm * -offtime(timep, offset) -const time_t * const timep; -const long offset; -{ - return gmtsub(timep, offset, &tm); -} - -#endif /* defined STD_INSPIRED */ - -/* -** Return the number of leap years through the end of the given year -** where, to make the math easy, the answer for year zero is defined as zero. -*/ - -static int -leaps_thru_end_of(y) -register const int y; -{ - return (y >= 0) ? (y / 4 - y / 100 + y / 400) : - -(leaps_thru_end_of(-(y + 1)) + 1); -} - -static struct tm * -timesub(timep, offset, sp, tmp) -const time_t * const timep; -const long offset; -const struct state * const sp; -struct tm * const tmp; -{ - const struct lsinfo * lp; - time_t tdays; - int idays; /* unsigned would be so 2003 */ - long rem; - int y; - const int * ip; - long corr; - int hit; - int i; - - corr = 0; - hit = 0; -#ifdef ALL_STATE - i = (sp == NULL) ? 0 : sp->leapcnt; -#endif /* defined ALL_STATE */ -#ifndef ALL_STATE - i = sp->leapcnt; -#endif /* State Farm */ - while (--i >= 0) { - lp = &sp->lsis[i]; - if (*timep >= lp->ls_trans) { - if (*timep == lp->ls_trans) { - hit = ((i == 0 && lp->ls_corr > 0) || - lp->ls_corr > sp->lsis[i - 1].ls_corr); - if (hit) - while (i > 0 && - sp->lsis[i].ls_trans == - sp->lsis[i - 1].ls_trans + 1 && - sp->lsis[i].ls_corr == - sp->lsis[i - 1].ls_corr + 1) { - ++hit; - --i; - } - } - corr = lp->ls_corr; - break; - } - } - y = EPOCH_YEAR; - tdays = *timep / SECSPERDAY; - rem = *timep - tdays * SECSPERDAY; - while (tdays < 0 || tdays >= year_lengths[isleap(y)]) { - int newy; - register time_t tdelta; - register int idelta; - register int leapdays; - - tdelta = tdays / DAYSPERLYEAR; - idelta = tdelta; - if (tdelta - idelta >= 1 || idelta - tdelta >= 1) - return NULL; - if (idelta == 0) - idelta = (tdays < 0) ? -1 : 1; - newy = y; - if (increment_overflow(&newy, idelta)) - return NULL; - leapdays = leaps_thru_end_of(newy - 1) - - leaps_thru_end_of(y - 1); - tdays -= ((time_t) newy - y) * DAYSPERNYEAR; - tdays -= leapdays; - y = newy; - } - { - register long seconds; - - seconds = tdays * SECSPERDAY + 0.5; - tdays = seconds / SECSPERDAY; - rem += seconds - tdays * SECSPERDAY; - } - /* - ** Given the range, we can now fearlessly cast... - */ - idays = tdays; - rem += offset - corr; - while (rem < 0) { - rem += SECSPERDAY; - --idays; - } - while (rem >= SECSPERDAY) { - rem -= SECSPERDAY; - ++idays; - } - while (idays < 0) { - if (increment_overflow(&y, -1)) - return NULL; - idays += year_lengths[isleap(y)]; - } - while (idays >= year_lengths[isleap(y)]) { - idays -= year_lengths[isleap(y)]; - if (increment_overflow(&y, 1)) - return NULL; - } - tmp->tm_year = y; - if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE)) - return NULL; - tmp->tm_yday = idays; - /* - ** The "extra" mods below avoid overflow problems. - */ - tmp->tm_wday = EPOCH_WDAY + - ((y - EPOCH_YEAR) % DAYSPERWEEK) * - (DAYSPERNYEAR % DAYSPERWEEK) + - leaps_thru_end_of(y - 1) - - leaps_thru_end_of(EPOCH_YEAR - 1) + - idays; - tmp->tm_wday %= DAYSPERWEEK; - if (tmp->tm_wday < 0) - tmp->tm_wday += DAYSPERWEEK; - tmp->tm_hour = (int) (rem / SECSPERHOUR); - rem %= SECSPERHOUR; - tmp->tm_min = (int) (rem / SECSPERMIN); - /* - ** A positive leap second requires a special - ** representation. This uses "... ??:59:60" et seq. - */ - tmp->tm_sec = (int) (rem % SECSPERMIN) + hit; - ip = mon_lengths[isleap(y)]; - for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon)) - idays -= ip[tmp->tm_mon]; - tmp->tm_mday = (int) (idays + 1); - tmp->tm_isdst = 0; -#ifdef TM_GMTOFF - tmp->TM_GMTOFF = offset; -#endif /* defined TM_GMTOFF */ - return tmp; -} - -char * -ctime(timep) -const time_t * const timep; -{ -/* -** Section 4.12.3.2 of X3.159-1989 requires that -** The ctime function converts the calendar time pointed to by timer -** to local time in the form of a string. It is equivalent to -** asctime(localtime(timer)) -*/ - return asctime(localtime(timep)); -} - -char * -ctime_r(timep, buf) -const time_t * const timep; -char * buf; -{ - struct tm mytm; - - return asctime_r(localtime_r(timep, &mytm), buf); -} - -/* -** Adapted from code provided by Robert Elz, who writes: -** The "best" way to do mktime I think is based on an idea of Bob -** Kridle's (so its said...) from a long time ago. -** It does a binary search of the time_t space. Since time_t's are -** just 32 bits, its a max of 32 iterations (even at 64 bits it -** would still be very reasonable). -*/ - -#ifndef WRONG -#define WRONG (-1) -#endif /* !defined WRONG */ - -/* -** Simplified normalize logic courtesy Paul Eggert. -*/ - -static int -increment_overflow(number, delta) -int * number; -int delta; -{ - int number0; - - number0 = *number; - *number += delta; - return (*number < number0) != (delta < 0); -} - -static int -long_increment_overflow(number, delta) -long * number; -int delta; -{ - long number0; - - number0 = *number; - *number += delta; - return (*number < number0) != (delta < 0); -} - -static int -normalize_overflow(tensptr, unitsptr, base) -int * const tensptr; -int * const unitsptr; -const int base; -{ - int tensdelta; - - tensdelta = (*unitsptr >= 0) ? - (*unitsptr / base) : - (-1 - (-1 - *unitsptr) / base); - *unitsptr -= tensdelta * base; - return increment_overflow(tensptr, tensdelta); -} - -static int -long_normalize_overflow(tensptr, unitsptr, base) -long * const tensptr; -int * const unitsptr; -const int base; -{ - register int tensdelta; - - tensdelta = (*unitsptr >= 0) ? - (*unitsptr / base) : - (-1 - (-1 - *unitsptr) / base); - *unitsptr -= tensdelta * base; - return long_increment_overflow(tensptr, tensdelta); -} - -static int -tmcomp(atmp, btmp) -const struct tm * const atmp; -const struct tm * const btmp; -{ - int result; - - if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && - (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && - (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && - (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && - (result = (atmp->tm_min - btmp->tm_min)) == 0) - result = atmp->tm_sec - btmp->tm_sec; - return result; -} - -static time_t -time2sub(tmp, funcp, offset, okayp, do_norm_secs) -struct tm * const tmp; -struct tm * (* const funcp)(const time_t*, long, struct tm*); -const long offset; -int * const okayp; -const int do_norm_secs; -{ - const struct state * sp; - int dir; - int i, j; - int saved_seconds; - long li; - time_t lo; - time_t hi; - long y; - time_t newt; - time_t t; - struct tm yourtm, mytm; - - *okayp = FALSE; - yourtm = *tmp; - if (do_norm_secs) { - if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec, - SECSPERMIN)) - return WRONG; - } - if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) - return WRONG; - if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) - return WRONG; - y = yourtm.tm_year; - if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR)) - return WRONG; - /* - ** Turn y into an actual year number for now. - ** It is converted back to an offset from TM_YEAR_BASE later. - */ - if (long_increment_overflow(&y, TM_YEAR_BASE)) - return WRONG; - while (yourtm.tm_mday <= 0) { - if (long_increment_overflow(&y, -1)) - return WRONG; - li = y + (1 < yourtm.tm_mon); - yourtm.tm_mday += year_lengths[isleap(li)]; - } - while (yourtm.tm_mday > DAYSPERLYEAR) { - li = y + (1 < yourtm.tm_mon); - yourtm.tm_mday -= year_lengths[isleap(li)]; - if (long_increment_overflow(&y, 1)) - return WRONG; - } - for ( ; ; ) { - i = mon_lengths[isleap(y)][yourtm.tm_mon]; - if (yourtm.tm_mday <= i) - break; - yourtm.tm_mday -= i; - if (++yourtm.tm_mon >= MONSPERYEAR) { - yourtm.tm_mon = 0; - if (long_increment_overflow(&y, 1)) - return WRONG; - } - } - if (long_increment_overflow(&y, -TM_YEAR_BASE)) - return WRONG; - yourtm.tm_year = y; - if (yourtm.tm_year != y) - return WRONG; - /* Don't go below 1900 for POLA */ - if (yourtm.tm_year < 0) - return WRONG; - if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN) - saved_seconds = 0; - else if (y + TM_YEAR_BASE < EPOCH_YEAR) { - /* - ** We can't set tm_sec to 0, because that might push the - ** time below the minimum representable time. - ** Set tm_sec to 59 instead. - ** This assumes that the minimum representable time is - ** not in the same minute that a leap second was deleted from, - ** which is a safer assumption than using 58 would be. - */ - if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) - return WRONG; - saved_seconds = yourtm.tm_sec; - yourtm.tm_sec = SECSPERMIN - 1; - } else { - saved_seconds = yourtm.tm_sec; - yourtm.tm_sec = 0; - } - /* - ** Do a binary search (this works whatever time_t's type is). - */ - if (!TYPE_SIGNED(time_t)) { - lo = 0; - hi = lo - 1; - } else if (!TYPE_INTEGRAL(time_t)) { - if (sizeof(time_t) > sizeof(float)) - hi = (time_t) DBL_MAX; - else hi = (time_t) FLT_MAX; - lo = -hi; - } else { - lo = 1; - for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i) - lo *= 2; - hi = -(lo + 1); - } - for ( ; ; ) { - t = lo / 2 + hi / 2; - if (t < lo) - t = lo; - else if (t > hi) - t = hi; - if ((*funcp)(&t, offset, &mytm) == NULL) { - /* - ** Assume that t is too extreme to be represented in - ** a struct tm; arrange things so that it is less - ** extreme on the next pass. - */ - dir = (t > 0) ? 1 : -1; - } else dir = tmcomp(&mytm, &yourtm); - if (dir != 0) { - if (t == lo) { - ++t; - if (t <= lo) - return WRONG; - ++lo; - } else if (t == hi) { - --t; - if (t >= hi) - return WRONG; - --hi; - } - if (lo > hi) - return WRONG; - if (dir > 0) - hi = t; - else lo = t; - continue; - } - if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) - break; - /* - ** Right time, wrong type. - ** Hunt for right time, right type. - ** It's okay to guess wrong since the guess - ** gets checked. - */ - sp = (const struct state *) - ((funcp == localsub) ? lclptr : gmtptr); -#ifdef ALL_STATE - if (sp == NULL) - return WRONG; -#endif /* defined ALL_STATE */ - for (i = sp->typecnt - 1; i >= 0; --i) { - if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) - continue; - for (j = sp->typecnt - 1; j >= 0; --j) { - if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) - continue; - newt = t + sp->ttis[j].tt_gmtoff - - sp->ttis[i].tt_gmtoff; - if ((*funcp)(&newt, offset, &mytm) == NULL) - continue; - if (tmcomp(&mytm, &yourtm) != 0) - continue; - if (mytm.tm_isdst != yourtm.tm_isdst) - continue; - /* - ** We have a match. - */ - t = newt; - goto label; - } - } - return WRONG; - } -label: - newt = t + saved_seconds; - if ((newt < t) != (saved_seconds < 0)) - return WRONG; - t = newt; - if ((*funcp)(&t, offset, tmp)) - *okayp = TRUE; - return t; -} - -static time_t -time2(tmp, funcp, offset, okayp) -struct tm * const tmp; -struct tm * (* const funcp)(const time_t*, long, struct tm*); -const long offset; -int * const okayp; -{ - time_t t; - - /* - ** First try without normalization of seconds - ** (in case tm_sec contains a value associated with a leap second). - ** If that fails, try with normalization of seconds. - */ - t = time2sub(tmp, funcp, offset, okayp, FALSE); - return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE); -} - -static time_t -time1(tmp, funcp, offset) -struct tm * const tmp; -struct tm * (* const funcp)(const time_t *, long, struct tm *); -const long offset; -{ - time_t t; - const struct state * sp; - int samei, otheri; - int sameind, otherind; - int i; - int nseen; - int seen[TZ_MAX_TYPES]; - int types[TZ_MAX_TYPES]; - int okay; - - if (tmp->tm_isdst > 1) - tmp->tm_isdst = 1; - t = time2(tmp, funcp, offset, &okay); -#ifdef PCTS - /* - ** PCTS code courtesy Grant Sullivan. - */ - if (okay) - return t; - if (tmp->tm_isdst < 0) - tmp->tm_isdst = 0; /* reset to std and try again */ -#endif /* defined PCTS */ -#ifndef PCTS - if (okay || tmp->tm_isdst < 0) - return t; -#endif /* !defined PCTS */ - /* - ** We're supposed to assume that somebody took a time of one type - ** and did some math on it that yielded a "struct tm" that's bad. - ** We try to divine the type they started from and adjust to the - ** type they need. - */ - sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr); -#ifdef ALL_STATE - if (sp == NULL) - return WRONG; -#endif /* defined ALL_STATE */ - for (i = 0; i < sp->typecnt; ++i) - seen[i] = FALSE; - nseen = 0; - for (i = sp->timecnt - 1; i >= 0; --i) - if (!seen[sp->types[i]]) { - seen[sp->types[i]] = TRUE; - types[nseen++] = sp->types[i]; - } - for (sameind = 0; sameind < nseen; ++sameind) { - samei = types[sameind]; - if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) - continue; - for (otherind = 0; otherind < nseen; ++otherind) { - otheri = types[otherind]; - if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) - continue; - tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - - sp->ttis[samei].tt_gmtoff; - tmp->tm_isdst = !tmp->tm_isdst; - t = time2(tmp, funcp, offset, &okay); - if (okay) - return t; - tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - - sp->ttis[samei].tt_gmtoff; - tmp->tm_isdst = !tmp->tm_isdst; - } - } - return WRONG; -} - -time_t -mktime(tmp) -struct tm * const tmp; -{ - time_t mktime_return_value; - _RWLOCK_RDLOCK(&lcl_rwlock); - tzset_basic(1); - mktime_return_value = time1(tmp, localsub, 0L); - _RWLOCK_UNLOCK(&lcl_rwlock); - return(mktime_return_value); -} - -#ifdef STD_INSPIRED - -time_t -timelocal(tmp) -struct tm * const tmp; -{ - tmp->tm_isdst = -1; /* in case it wasn't initialized */ - return mktime(tmp); -} - -time_t -timegm(tmp) -struct tm * const tmp; -{ - tmp->tm_isdst = 0; - return time1(tmp, gmtsub, 0L); -} - -time_t -timeoff(tmp, offset) -struct tm * const tmp; -const long offset; -{ - tmp->tm_isdst = 0; - return time1(tmp, gmtsub, offset); -} - -#endif /* defined STD_INSPIRED */ - -#ifdef CMUCS - -/* -** The following is supplied for compatibility with -** previous versions of the CMUCS runtime library. -*/ - -long -gtime(tmp) -struct tm * const tmp; -{ - const time_t t = mktime(tmp); - - if (t == WRONG) - return -1; - return t; -} - -#endif /* defined CMUCS */ - -/* -** XXX--is the below the right way to conditionalize?? -*/ - -#ifdef STD_INSPIRED - -/* -** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599 -** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which -** is not the case if we are accounting for leap seconds. -** So, we provide the following conversion routines for use -** when exchanging timestamps with POSIX conforming systems. -*/ - -static long -leapcorr(timep) -time_t * timep; -{ - struct state * sp; - struct lsinfo * lp; - int i; - - sp = lclptr; - i = sp->leapcnt; - while (--i >= 0) { - lp = &sp->lsis[i]; - if (*timep >= lp->ls_trans) - return lp->ls_corr; - } - return 0; -} - -time_t -time2posix(t) -time_t t; -{ - tzset(); - return t - leapcorr(&t); -} - -time_t -posix2time(t) -time_t t; -{ - time_t x; - time_t y; - - tzset(); - /* - ** For a positive leap second hit, the result - ** is not unique. For a negative leap second - ** hit, the corresponding time doesn't exist, - ** so we return an adjacent second. - */ - x = t + leapcorr(&t); - y = x - leapcorr(&x); - if (y < t) { - do { - x++; - y = x - leapcorr(&x); - } while (y < t); - if (t != y) - return x - 1; - } else if (y > t) { - do { - --x; - y = x - leapcorr(&x); - } while (y > t); - if (t != y) - return x + 1; - } - return x; -} - -#endif /* defined STD_INSPIRED */ diff --git a/lib/libc/stdtime/private.h b/lib/libc/stdtime/private.h deleted file mode 100644 index dda5bef..0000000 --- a/lib/libc/stdtime/private.h +++ /dev/null @@ -1,326 +0,0 @@ -#ifndef PRIVATE_H - -#define PRIVATE_H - -/* -** This file is in the public domain, so clarified as of -** 1996-06-05 by Arthur David Olson. -** -** $FreeBSD$ -*/ - -/* Stuff moved from Makefile.inc to reduce clutter */ -#ifndef TM_GMTOFF -#define TM_GMTOFF tm_gmtoff -#define TM_ZONE tm_zone -#define STD_INSPIRED 1 -#define PCTS 1 -#define HAVE_LONG_DOUBLE 1 -#define HAVE_STRERROR 1 -#define HAVE_UNISTD_H 1 -#define LOCALE_HOME _PATH_LOCALE -#define TZDIR "/usr/share/zoneinfo" -#endif /* ndef TM_GMTOFF */ - -/* -** This header is for use ONLY with the time conversion code. -** There is no guarantee that it will remain unchanged, -** or that it will remain at all. -** Do NOT copy it to any system include directory. -** Thank you! -*/ - -/* -** ID -*/ - -#ifndef lint -#ifndef NOID -/* -static char privatehid[] = "@(#)private.h 8.6"; -*/ -#endif /* !defined NOID */ -#endif /* !defined lint */ - -#define GRANDPARENTED "Local time zone must be set--see zic manual page" - -/* -** Defaults for preprocessor symbols. -** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'. -*/ - -#ifndef HAVE_ADJTIME -#define HAVE_ADJTIME 1 -#endif /* !defined HAVE_ADJTIME */ - -#ifndef HAVE_GETTEXT -#define HAVE_GETTEXT 0 -#endif /* !defined HAVE_GETTEXT */ - -#ifndef HAVE_INCOMPATIBLE_CTIME_R -#define HAVE_INCOMPATIBLE_CTIME_R 0 -#endif /* !defined INCOMPATIBLE_CTIME_R */ - -#ifndef HAVE_SETTIMEOFDAY -#define HAVE_SETTIMEOFDAY 3 -#endif /* !defined HAVE_SETTIMEOFDAY */ - -#ifndef HAVE_SYMLINK -#define HAVE_SYMLINK 1 -#endif /* !defined HAVE_SYMLINK */ - -#ifndef HAVE_SYS_STAT_H -#define HAVE_SYS_STAT_H 1 -#endif /* !defined HAVE_SYS_STAT_H */ - -#ifndef HAVE_SYS_WAIT_H -#define HAVE_SYS_WAIT_H 1 -#endif /* !defined HAVE_SYS_WAIT_H */ - -#ifndef HAVE_UNISTD_H -#define HAVE_UNISTD_H 1 -#endif /* !defined HAVE_UNISTD_H */ - -#ifndef HAVE_UTMPX_H -#define HAVE_UTMPX_H 0 -#endif /* !defined HAVE_UTMPX_H */ - -#ifndef LOCALE_HOME -#define LOCALE_HOME "/usr/lib/locale" -#endif /* !defined LOCALE_HOME */ - -#if HAVE_INCOMPATIBLE_CTIME_R -#define asctime_r _incompatible_asctime_r -#define ctime_r _incompatible_ctime_r -#endif /* HAVE_INCOMPATIBLE_CTIME_R */ - -/* -** Nested includes -*/ - -#include "sys/types.h" /* for time_t */ -#include "stdio.h" -#include "errno.h" -#include "string.h" -#include "limits.h" /* for CHAR_BIT et al. */ -#include "time.h" -#include "stdlib.h" - -#if HAVE_GETTEXT -#include "libintl.h" -#endif /* HAVE_GETTEXT */ - -#if HAVE_SYS_WAIT_H -#include /* for WIFEXITED and WEXITSTATUS */ -#endif /* HAVE_SYS_WAIT_H */ - -#ifndef WIFEXITED -#define WIFEXITED(status) (((status) & 0xff) == 0) -#endif /* !defined WIFEXITED */ -#ifndef WEXITSTATUS -#define WEXITSTATUS(status) (((status) >> 8) & 0xff) -#endif /* !defined WEXITSTATUS */ - -#if HAVE_UNISTD_H -#include "unistd.h" /* for F_OK, R_OK, and other POSIX goodness */ -#endif /* HAVE_UNISTD_H */ - -#if !(HAVE_UNISTD_H) -#ifndef F_OK -#define F_OK 0 -#endif /* !defined F_OK */ -#ifndef R_OK -#define R_OK 4 -#endif /* !defined R_OK */ -#endif /* !(HAVE_UNISTD_H) */ - -/* Unlike 's isdigit, this also works if c < 0 | c > UCHAR_MAX. */ -#define is_digit(c) ((unsigned)(c) - '0' <= 9) - -/* -** Define HAVE_STDINT_H's default value here, rather than at the -** start, since __GLIBC__'s value depends on previously-included -** files. -** (glibc 2.1 and later have stdint.h, even with pre-C99 compilers.) -*/ -#ifndef HAVE_STDINT_H -#define HAVE_STDINT_H \ - (199901 <= __STDC_VERSION__ || \ - 2 < (__GLIBC__ + (0 < __GLIBC_MINOR__))) -#endif /* !defined HAVE_STDINT_H */ - -#if HAVE_STDINT_H -#include "stdint.h" -#endif /* !HAVE_STDINT_H */ - -#ifndef INT_FAST64_MAX -/* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */ -#if defined LLONG_MAX || defined __LONG_LONG_MAX__ -typedef long long int_fast64_t; -#else /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */ -#if (LONG_MAX >> 31) < 0xffffffff -Please use a compiler that supports a 64-bit integer type (or wider); -you may need to compile with "-DHAVE_STDINT_H". -#endif /* (LONG_MAX >> 31) < 0xffffffff */ -typedef long int_fast64_t; -#endif /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */ -#endif /* !defined INT_FAST64_MAX */ - -#ifndef INT32_MAX -#define INT32_MAX 0x7fffffff -#endif /* !defined INT32_MAX */ -#ifndef INT32_MIN -#define INT32_MIN (-1 - INT32_MAX) -#endif /* !defined INT32_MIN */ - -/* -** Workarounds for compilers/systems. -*/ - -/* -** Some time.h implementations don't declare asctime_r. -** Others might define it as a macro. -** Fix the former without affecting the latter. -*/ - -#ifndef asctime_r -extern char * asctime_r(struct tm const *, char *); -#endif - -/* -** Private function declarations. -*/ - -char * icalloc(int nelem, int elsize); -char * icatalloc(char * old, const char * new); -char * icpyalloc(const char * string); -char * imalloc(int n); -void * irealloc(void * pointer, int size); -void icfree(char * pointer); -void ifree(char * pointer); -const char * scheck(const char * string, const char * format); - -/* -** Finally, some convenience items. -*/ - -#ifndef TRUE -#define TRUE 1 -#endif /* !defined TRUE */ - -#ifndef FALSE -#define FALSE 0 -#endif /* !defined FALSE */ - -#ifndef TYPE_BIT -#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT) -#endif /* !defined TYPE_BIT */ - -#ifndef TYPE_SIGNED -#define TYPE_SIGNED(type) (((type) -1) < 0) -#endif /* !defined TYPE_SIGNED */ - -/* -** Since the definition of TYPE_INTEGRAL contains floating point numbers, -** it cannot be used in preprocessor directives. -*/ - -#ifndef TYPE_INTEGRAL -#define TYPE_INTEGRAL(type) (((type) 0.5) != 0.5) -#endif /* !defined TYPE_INTEGRAL */ - -/* -** Since the definition of TYPE_INTEGRAL contains floating point numbers, -** it cannot be used in preprocessor directives. -*/ - -#ifndef TYPE_INTEGRAL -#define TYPE_INTEGRAL(type) (((type) 0.5) != 0.5) -#endif /* !defined TYPE_INTEGRAL */ - -#ifndef INT_STRLEN_MAXIMUM -/* -** 302 / 1000 is log10(2.0) rounded up. -** Subtract one for the sign bit if the type is signed; -** add one for integer division truncation; -** add one more for a minus sign if the type is signed. -*/ -#define INT_STRLEN_MAXIMUM(type) \ - ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \ - 1 + TYPE_SIGNED(type)) -#endif /* !defined INT_STRLEN_MAXIMUM */ - -/* -** INITIALIZE(x) -*/ - -#ifndef GNUC_or_lint -#ifdef lint -#define GNUC_or_lint -#endif /* defined lint */ -#ifndef lint -#ifdef __GNUC__ -#define GNUC_or_lint -#endif /* defined __GNUC__ */ -#endif /* !defined lint */ -#endif /* !defined GNUC_or_lint */ - -#ifndef INITIALIZE -#ifdef GNUC_or_lint -#define INITIALIZE(x) ((x) = 0) -#endif /* defined GNUC_or_lint */ -#ifndef GNUC_or_lint -#define INITIALIZE(x) -#endif /* !defined GNUC_or_lint */ -#endif /* !defined INITIALIZE */ - -/* -** For the benefit of GNU folk... -** `_(MSGID)' uses the current locale's message library string for MSGID. -** The default is to use gettext if available, and use MSGID otherwise. -*/ - -#ifndef _ -#if HAVE_GETTEXT -#define _(msgid) gettext(msgid) -#else /* !HAVE_GETTEXT */ -#define _(msgid) msgid -#endif /* !HAVE_GETTEXT */ -#endif /* !defined _ */ - -#ifndef TZ_DOMAIN -#define TZ_DOMAIN "tz" -#endif /* !defined TZ_DOMAIN */ - -#if HAVE_INCOMPATIBLE_CTIME_R -#undef asctime_r -#undef ctime_r -char *asctime_r(struct tm const *, char *); -char *ctime_r(time_t const *, char *); -#endif /* HAVE_INCOMPATIBLE_CTIME_R */ - -#ifndef YEARSPERREPEAT -#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */ -#endif /* !defined YEARSPERREPEAT */ - -/* -** The Gregorian year averages 365.2425 days, which is 31556952 seconds. -*/ - -#ifndef AVGSECSPERYEAR -#define AVGSECSPERYEAR 31556952L -#endif /* !defined AVGSECSPERYEAR */ - -#ifndef SECSPERREPEAT -#define SECSPERREPEAT ((int_fast64_t) YEARSPERREPEAT * (int_fast64_t) AVGSECSPERYEAR) -#endif /* !defined SECSPERREPEAT */ - -#ifndef SECSPERREPEAT_BITS -#define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */ -#endif /* !defined SECSPERREPEAT_BITS */ - -/* -** UNIX was a registered trademark of The Open Group in 2003. -*/ - -#endif /* !defined PRIVATE_H */ diff --git a/lib/libc/stdtime/time2posix.3 b/lib/libc/stdtime/time2posix.3 deleted file mode 100644 index 1a1ec95..0000000 --- a/lib/libc/stdtime/time2posix.3 +++ /dev/null @@ -1,123 +0,0 @@ -.\" $FreeBSD$ -.\" -.Dd September 11, 2005 -.Dt TIME2POSIX 3 -.Os -.Sh NAME -.Nm time2posix , -.Nm posix2time -.Nd convert seconds since the Epoch -.Sh LIBRARY -.Lb libc -.Sh SYNOPSIS -.In time.h -.Ft time_t -.Fn time2posix "time_t t" -.Ft time_t -.Fn posix2time "time_t t" -.Sh DESCRIPTION -.St -p1003.1-88 -legislates that a time_t value of -536457599 shall correspond to "Wed Dec 31 23:59:59 GMT 1986." -This effectively implies that POSIX time_t's cannot include leap -seconds and, -therefore, -that the system time must be adjusted as each leap occurs. -.Pp -If the time package is configured with leap-second support -enabled, -however, -no such adjustment is needed and -time_t values continue to increase over leap events -(as a true `seconds since...' value). -This means that these values will differ from those required by POSIX -by the net number of leap seconds inserted since the Epoch. -.Pp -Typically this is not a problem as the type time_t is intended -to be -(mostly) -opaque\(emtime_t values should only be obtained-from and -passed-to functions such as -.Xr time 3 , -.Xr localtime 3 , -.Xr mktime 3 -and -.Xr difftime 3 . -However, -.St -p1003.1-88 -gives an arithmetic -expression for directly computing a time_t value from a given date/time, -and the same relationship is assumed by some -(usually older) -applications. -Any programs creating/dissecting time_t's -using such a relationship will typically not handle intervals -over leap seconds correctly. -.Pp -The -.Fn time2posix -and -.Fn posix2time -functions are provided to address this time_t mismatch by converting -between local time_t values and their POSIX equivalents. -This is done by accounting for the number of time-base changes that -would have taken place on a POSIX system as leap seconds were inserted -or deleted. -These converted values can then be used in lieu of correcting the older -applications, -or when communicating with POSIX-compliant systems. -.Pp -The -.Fn time2posix -function is single-valued. -That is, -every local time_t -corresponds to a single POSIX time_t. -The -.Fn posix2time -function is less well-behaved: -for a positive leap second hit the result is not unique, -and for a negative leap second hit the corresponding -POSIX time_t does not exist so an adjacent value is returned. -Both of these are good indicators of the inferiority of the -POSIX representation. -.Pp -The following table summarizes the relationship between time_t -and its conversion to, -and back from, -the POSIX representation over the leap second inserted at the end of June, -1993. -.Bl -column "93/06/30" "23:59:59" "A+0" "X=time2posix(T)" -.It Sy "DATE TIME T X=time2posix(T) posix2time(X)" -.It "93/06/30 23:59:59 A+0 B+0 A+0" -.It "93/06/30 23:59:60 A+1 B+1 A+1 or A+2" -.It "93/07/01 00:00:00 A+2 B+1 A+1 or A+2" -.It "93/07/01 00:00:01 A+3 B+2 A+3" -.El -.Pp -A leap second deletion would look like... -.Bl -column "??/06/30" "23:59:58" "A+0" "X=time2posix(T)" -.It Sy "DATE TIME T X=time2posix(T) posix2time(X)" -.It "??/06/30 23:59:58 A+0 B+0 A+0" -.It "??/07/01 00:00:00 A+1 B+2 A+1" -.It "??/07/01 00:00:01 A+2 B+3 A+2" -.El -.Pp -.D1 No "[Note: posix2time(B+1) => A+0 or A+1]" -.Pp -If leap-second support is not enabled, -local time_t's and -POSIX time_t's are equivalent, -and both -.Fn time2posix -and -.Fn posix2time -degenerate to the identity function. -.Sh "SEE ALSO" -.Xr difftime 3 , -.Xr localtime 3 , -.Xr mktime 3 , -.Xr time 3 -.\" @(#)time2posix.3 8.2 -.\" This file is in the public domain, so clarified as of -.\" 1996-06-05 by Arthur David Olson. diff --git a/lib/libc/stdtime/tzfile.5 b/lib/libc/stdtime/tzfile.5 deleted file mode 100644 index 1606b5a..0000000 --- a/lib/libc/stdtime/tzfile.5 +++ /dev/null @@ -1,152 +0,0 @@ -.\" $FreeBSD$ -.Dd September 13, 1994 -.Dt TZFILE 5 -.Os -.Sh NAME -.Nm tzfile -.Nd timezone information -.Sh SYNOPSIS -.Fd #include \&"/usr/src/lib/libc/stdtime/tzfile.h\&" -.Sh DESCRIPTION -The time zone information files used by -.Xr tzset 3 -begin with the magic characters -.Dq Li TZif -to identify them as -time zone information files, -followed by a character identifying the version of the file's format -(as of 2005, either an ASCII NUL or a '2') -followed by fifteen bytes containing zeroes reserved for future use, -followed by four four-byte values -written in a ``standard'' byte order -(the high-order byte of the value is written first). -These values are, -in order: -.Pp -.Bl -tag -compact -width tzh_ttisstdcnt -.It Va tzh_ttisgmtcnt -The number of UTC/local indicators stored in the file. -.It Va tzh_ttisstdcnt -The number of standard/wall indicators stored in the file. -.It Va tzh_leapcnt -The number of leap seconds for which data is stored in the file. -.It Va tzh_timecnt -The number of ``transition times'' for which data is stored -in the file. -.It Va tzh_typecnt -The number of ``local time types'' for which data is stored -in the file (must not be zero). -.It Va tzh_charcnt -The number of characters of ``time zone abbreviation strings'' -stored in the file. -.El -.Pp -The above header is followed by -.Va tzh_timecnt -four-byte values of type -.Fa long , -sorted in ascending order. -These values are written in ``standard'' byte order. -Each is used as a transition time (as returned by -.Xr time 3 ) -at which the rules for computing local time change. -Next come -.Va tzh_timecnt -one-byte values of type -.Fa "unsigned char" ; -each one tells which of the different types of ``local time'' types -described in the file is associated with the same-indexed transition time. -These values serve as indices into an array of -.Fa ttinfo -structures (with -.Fa tzh_typecnt -entries) that appears next in the file; -these structures are defined as follows: -.Pp -.Bd -literal -offset indent -struct ttinfo { - long tt_gmtoff; - int tt_isdst; - unsigned int tt_abbrind; -}; -.Ed -.Pp -Each structure is written as a four-byte value for -.Va tt_gmtoff -of type -.Fa long , -in a standard byte order, followed by a one-byte value for -.Va tt_isdst -and a one-byte value for -.Va tt_abbrind . -In each structure, -.Va tt_gmtoff -gives the number of seconds to be added to UTC, -.Li tt_isdst -tells whether -.Li tm_isdst -should be set by -.Xr localtime 3 -and -.Va tt_abbrind -serves as an index into the array of time zone abbreviation characters -that follow the -.Li ttinfo -structure(s) in the file. -.Pp -Then there are -.Va tzh_leapcnt -pairs of four-byte values, written in standard byte order; -the first value of each pair gives the time -(as returned by -.Xr time 3 ) -at which a leap second occurs; -the second gives the -.Em total -number of leap seconds to be applied after the given time. -The pairs of values are sorted in ascending order by time. -.Pp -Then there are -.Va tzh_ttisstdcnt -standard/wall indicators, each stored as a one-byte value; -they tell whether the transition times associated with local time types -were specified as standard time or wall clock time, -and are used when a time zone file is used in handling POSIX-style -time zone environment variables. -.Pp -Finally there are -.Va tzh_ttisgmtcnt -UTC/local indicators, each stored as a one-byte value; -they tell whether the transition times associated with local time types -were specified as UTC or local time, -and are used when a time zone file is used in handling POSIX-style -time zone environment variables. -.Pp -.Nm localtime -uses the first standard-time -.Li ttinfo -structure in the file -(or simply the first -.Li ttinfo -structure in the absence of a standard-time structure) -if either -.Li tzh_timecnt -is zero or the time argument is less than the first transition time recorded -in the file. -.Pp -For version-2-format time zone files, -the above header and data is followed by a second header and data, -identical in format except that eight bytes are used for each -transition time or leap second time. -After the second header and data comes a newline-enclosed, -POSIX-TZ-environment-variable-style string for use in handling instants -after the last transition time stored in the file -(with nothing between the newlines if there is no POSIX representation for -such instants). -.Sh SEE ALSO -.Xr ctime 3 , -.Xr time2posix 3 , -.Xr zic 8 -.\" @(#)tzfile.5 8.3 -.\" This file is in the public domain, so clarified as of -.\" 1996-06-05 by Arthur David Olson. diff --git a/lib/libc/stdtime/tzfile.h b/lib/libc/stdtime/tzfile.h deleted file mode 100644 index 85b945e..0000000 --- a/lib/libc/stdtime/tzfile.h +++ /dev/null @@ -1,184 +0,0 @@ -#ifndef TZFILE_H -#define TZFILE_H - - -/* -** This file is in the public domain, so clarified as of -** 1996-06-05 by Arthur David Olson. -** -** $FreeBSD$ -*/ - -/* -** This header is for use ONLY with the time conversion code. -** There is no guarantee that it will remain unchanged, -** or that it will remain at all. -** Do NOT copy it to any system include directory. -** Thank you! -*/ - -/* -** ID -*/ - -#ifndef lint -#ifndef NOID -/* -static char tzfilehid[] = "@(#)tzfile.h 8.1"; -*/ -#endif /* !defined NOID */ -#endif /* !defined lint */ - -/* -** Information about time zone files. -*/ - -#ifndef TZDIR -#define TZDIR "/usr/share/zoneinfo" /* Time zone object file directory */ -#endif /* !defined TZDIR */ - -#ifndef TZDEFAULT -#define TZDEFAULT "/etc/localtime" -#endif /* !defined TZDEFAULT */ - -#ifndef TZDEFRULES -#define TZDEFRULES "posixrules" -#endif /* !defined TZDEFRULES */ - -/* -** Each file begins with. . . -*/ - -#define TZ_MAGIC "TZif" - -struct tzhead { - char tzh_magic[4]; /* TZ_MAGIC */ - char tzh_version[1]; /* '\0' or '2' as of 2005 */ - char tzh_reserved[15]; /* reserved--must be zero */ - char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */ - char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */ - char tzh_leapcnt[4]; /* coded number of leap seconds */ - char tzh_timecnt[4]; /* coded number of transition times */ - char tzh_typecnt[4]; /* coded number of local time types */ - char tzh_charcnt[4]; /* coded number of abbr. chars */ -}; - -/* -** . . .followed by. . . -** -** tzh_timecnt (char [4])s coded transition times a la time(2) -** tzh_timecnt (unsigned char)s types of local time starting at above -** tzh_typecnt repetitions of -** one (char [4]) coded UTC offset in seconds -** one (unsigned char) used to set tm_isdst -** one (unsigned char) that's an abbreviation list index -** tzh_charcnt (char)s '\0'-terminated zone abbreviations -** tzh_leapcnt repetitions of -** one (char [4]) coded leap second transition times -** one (char [4]) total correction after above -** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition -** time is standard time, if FALSE, -** transition time is wall clock time -** if absent, transition times are -** assumed to be wall clock time -** tzh_ttisgmtcnt (char)s indexed by type; if TRUE, transition -** time is UTC, if FALSE, -** transition time is local time -** if absent, transition times are -** assumed to be local time -*/ - -/* -** If tzh_version is '2' or greater, the above is followed by a second instance -** of tzhead and a second instance of the data in which each coded transition -** time uses 8 rather than 4 chars, -** then a POSIX-TZ-environment-variable-style string for use in handling -** instants after the last transition time stored in the file -** (with nothing between the newlines if there is no POSIX representation for -** such instants). -*/ - -/* -** In the current implementation, "tzset()" refuses to deal with files that -** exceed any of the limits below. -*/ - -#ifndef TZ_MAX_TIMES -#define TZ_MAX_TIMES 1200 -#endif /* !defined TZ_MAX_TIMES */ - -#ifndef TZ_MAX_TYPES -#ifndef NOSOLAR -#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */ -#endif /* !defined NOSOLAR */ -#ifdef NOSOLAR -/* -** Must be at least 14 for Europe/Riga as of Jan 12 1995, -** as noted by Earl Chew. -*/ -#define TZ_MAX_TYPES 20 /* Maximum number of local time types */ -#endif /* !defined NOSOLAR */ -#endif /* !defined TZ_MAX_TYPES */ - -#ifndef TZ_MAX_CHARS -#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */ - /* (limited by what unsigned chars can hold) */ -#endif /* !defined TZ_MAX_CHARS */ - -#ifndef TZ_MAX_LEAPS -#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */ -#endif /* !defined TZ_MAX_LEAPS */ - -#define SECSPERMIN 60 -#define MINSPERHOUR 60 -#define HOURSPERDAY 24 -#define DAYSPERWEEK 7 -#define DAYSPERNYEAR 365 -#define DAYSPERLYEAR 366 -#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) -#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY) -#define MONSPERYEAR 12 - -#define TM_SUNDAY 0 -#define TM_MONDAY 1 -#define TM_TUESDAY 2 -#define TM_WEDNESDAY 3 -#define TM_THURSDAY 4 -#define TM_FRIDAY 5 -#define TM_SATURDAY 6 - -#define TM_JANUARY 0 -#define TM_FEBRUARY 1 -#define TM_MARCH 2 -#define TM_APRIL 3 -#define TM_MAY 4 -#define TM_JUNE 5 -#define TM_JULY 6 -#define TM_AUGUST 7 -#define TM_SEPTEMBER 8 -#define TM_OCTOBER 9 -#define TM_NOVEMBER 10 -#define TM_DECEMBER 11 - -#define TM_YEAR_BASE 1900 - -#define EPOCH_YEAR 1970 -#define EPOCH_WDAY TM_THURSDAY - -#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) - -/* -** Since everything in isleap is modulo 400 (or a factor of 400), we know that -** isleap(y) == isleap(y % 400) -** and so -** isleap(a + b) == isleap((a + b) % 400) -** or -** isleap(a + b) == isleap(a % 400 + b % 400) -** This is true even if % means modulo rather than Fortran remainder -** (which is allowed by C89 but not C99). -** We use this to avoid addition overflow problems. -*/ - -#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) - -#endif /* !defined TZFILE_H */ -- cgit v1.1 From dfdee678fd03cac5ff7c47a270bdf5bd2c745f59 Mon Sep 17 00:00:00 2001 From: jh Date: Sun, 28 Feb 2010 13:31:29 +0000 Subject: In _gettemp(), check that the length of the path doesn't exceed MAXPATHLEN. Otherwise the path name (or part of it) may not fit to carrybuf causing a buffer overflow. PR: bin/140228 Suggested by: jilles --- lib/libc/stdio/mktemp.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/stdio/mktemp.c b/lib/libc/stdio/mktemp.c index 3f1e699..a30b930 100644 --- a/lib/libc/stdio/mktemp.c +++ b/lib/libc/stdio/mktemp.c @@ -116,6 +116,10 @@ _gettemp(path, doopen, domkdir, slen) for (trv = path; *trv != '\0'; ++trv) ; + if (trv - path >= MAXPATHLEN) { + errno = ENAMETOOLONG; + return (0); + } trv -= slen; suffp = trv; --trv; -- cgit v1.1 From 67dd56fb510222481fc77553f9ef25a5fd1f9620 Mon Sep 17 00:00:00 2001 From: jasone Date: Sun, 28 Feb 2010 22:57:13 +0000 Subject: Rewrite red-black trees to do lazy balance fixup. This improves insert/remove speed by ~30%. --- lib/libc/stdlib/malloc.c | 30 +- lib/libc/stdlib/rb.h | 1579 ++++++++++++++++++++++++---------------------- 2 files changed, 837 insertions(+), 772 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c index de7a4c0..295a168 100644 --- a/lib/libc/stdlib/malloc.c +++ b/lib/libc/stdlib/malloc.c @@ -194,6 +194,7 @@ __FBSDID("$FreeBSD$"); #include "un-namespace.h" +#define RB_COMPACT #include "rb.h" #if (defined(MALLOC_TCACHE) && defined(MALLOC_STATS)) #include "qr.h" @@ -1746,7 +1747,7 @@ extent_szad_comp(extent_node_t *a, extent_node_t *b) } /* Wrap red-black tree macros in functions. */ -rb_wrap(__unused static, extent_tree_szad_, extent_tree_t, extent_node_t, +rb_gen(__unused static, extent_tree_szad_, extent_tree_t, extent_node_t, link_szad, extent_szad_comp) #endif @@ -1760,7 +1761,7 @@ extent_ad_comp(extent_node_t *a, extent_node_t *b) } /* Wrap red-black tree macros in functions. */ -rb_wrap(__unused static, extent_tree_ad_, extent_tree_t, extent_node_t, link_ad, +rb_gen(__unused static, extent_tree_ad_, extent_tree_t, extent_node_t, link_ad, extent_ad_comp) /* @@ -2346,7 +2347,7 @@ arena_chunk_comp(arena_chunk_t *a, arena_chunk_t *b) } /* Wrap red-black tree macros in functions. */ -rb_wrap(__unused static, arena_chunk_tree_dirty_, arena_chunk_tree_t, +rb_gen(__unused static, arena_chunk_tree_dirty_, arena_chunk_tree_t, arena_chunk_t, link_dirty, arena_chunk_comp) static inline int @@ -2362,7 +2363,7 @@ arena_run_comp(arena_chunk_map_t *a, arena_chunk_map_t *b) } /* Wrap red-black tree macros in functions. */ -rb_wrap(__unused static, arena_run_tree_, arena_run_tree_t, arena_chunk_map_t, +rb_gen(__unused static, arena_run_tree_, arena_run_tree_t, arena_chunk_map_t, link, arena_run_comp) static inline int @@ -2394,7 +2395,7 @@ arena_avail_comp(arena_chunk_map_t *a, arena_chunk_map_t *b) } /* Wrap red-black tree macros in functions. */ -rb_wrap(__unused static, arena_avail_tree_, arena_avail_tree_t, +rb_gen(__unused static, arena_avail_tree_, arena_avail_tree_t, arena_chunk_map_t, link, arena_avail_comp) static inline void @@ -2824,6 +2825,18 @@ arena_run_alloc(arena_t *arena, size_t size, bool large, bool zero) return (run); } +#ifdef MALLOC_DEBUG +static arena_chunk_t * +chunks_dirty_iter_cb(arena_chunk_tree_t *tree, arena_chunk_t *chunk, void *arg) +{ + size_t *ndirty = (size_t *)arg; + + assert(chunk->dirtied); + *ndirty += chunk->ndirty; + return (NULL); +} +#endif + static void arena_purge(arena_t *arena) { @@ -2832,11 +2845,8 @@ arena_purge(arena_t *arena) #ifdef MALLOC_DEBUG size_t ndirty = 0; - rb_foreach_begin(arena_chunk_t, link_dirty, &arena->chunks_dirty, - chunk) { - assert(chunk->dirtied); - ndirty += chunk->ndirty; - } rb_foreach_end(arena_chunk_t, link_dirty, &arena->chunks_dirty, chunk) + arena_chunk_tree_dirty_iter(&arena->chunks_dirty, NULL, + chunks_dirty_iter_cb, (void *)&ndirty); assert(ndirty == arena->ndirty); #endif assert((arena->nactive >> opt_lg_dirty_mult) < arena->ndirty); diff --git a/lib/libc/stdlib/rb.h b/lib/libc/stdlib/rb.h index 80875b0..baaec7f 100644 --- a/lib/libc/stdlib/rb.h +++ b/lib/libc/stdlib/rb.h @@ -1,6 +1,7 @@ -/****************************************************************************** +/*- + ******************************************************************************* * - * Copyright (C) 2008 Jason Evans . + * Copyright (C) 2008-2010 Jason Evans . * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,40 +30,23 @@ * ****************************************************************************** * - * cpp macro implementation of left-leaning red-black trees. + * cpp macro implementation of left-leaning 2-3 red-black trees. Parent + * pointers are not used, and color bits are stored in the least significant + * bit of right-child pointers (if RB_COMPACT is defined), thus making node + * linkage as compact as is possible for red-black trees. * * Usage: * - * (Optional, see assert(3).) - * #define NDEBUG - * - * (Required.) + * #include + * #include + * #define NDEBUG // (Optional, see assert(3).) * #include + * #define RB_COMPACT // (Optional, embed color bits in right-child pointers.) * #include * ... * - * All operations are done non-recursively. Parent pointers are not used, and - * color bits are stored in the least significant bit of right-child pointers, - * thus making node linkage as compact as is possible for red-black trees. - * - * Some macros use a comparison function pointer, which is expected to have the - * following prototype: - * - * int (a_cmp *)(a_type *a_node, a_type *a_other); - * ^^^^^^ - * or a_key - * - * Interpretation of comparision function return values: - * - * -1 : a_node < a_other - * 0 : a_node == a_other - * 1 : a_node > a_other - * - * In all cases, the a_node or a_key macro argument is the first argument to the - * comparison function, which makes it possible to write comparison functions - * that treat the first argument specially. - * - ******************************************************************************/ + ******************************************************************************* + */ #ifndef RB_H_ #define RB_H_ @@ -70,12 +54,21 @@ #include __FBSDID("$FreeBSD$"); +#ifdef RB_COMPACT /* Node structure. */ #define rb_node(a_type) \ struct { \ a_type *rbn_left; \ a_type *rbn_right_red; \ } +#else +#define rb_node(a_type) \ +struct { \ + a_type *rbn_left; \ + a_type *rbn_right; \ + bool rbn_red; \ +} +#endif /* Root structure. */ #define rb_tree(a_type) \ @@ -85,863 +78,925 @@ struct { \ } /* Left accessors. */ -#define rbp_left_get(a_type, a_field, a_node) \ +#define rbtn_left_get(a_type, a_field, a_node) \ ((a_node)->a_field.rbn_left) -#define rbp_left_set(a_type, a_field, a_node, a_left) do { \ +#define rbtn_left_set(a_type, a_field, a_node, a_left) do { \ (a_node)->a_field.rbn_left = a_left; \ } while (0) +#ifdef RB_COMPACT /* Right accessors. */ -#define rbp_right_get(a_type, a_field, a_node) \ +#define rbtn_right_get(a_type, a_field, a_node) \ ((a_type *) (((intptr_t) (a_node)->a_field.rbn_right_red) \ & ((ssize_t)-2))) -#define rbp_right_set(a_type, a_field, a_node, a_right) do { \ +#define rbtn_right_set(a_type, a_field, a_node, a_right) do { \ (a_node)->a_field.rbn_right_red = (a_type *) (((uintptr_t) a_right) \ | (((uintptr_t) (a_node)->a_field.rbn_right_red) & ((size_t)1))); \ } while (0) /* Color accessors. */ -#define rbp_red_get(a_type, a_field, a_node) \ +#define rbtn_red_get(a_type, a_field, a_node) \ ((bool) (((uintptr_t) (a_node)->a_field.rbn_right_red) \ & ((size_t)1))) -#define rbp_color_set(a_type, a_field, a_node, a_red) do { \ +#define rbtn_color_set(a_type, a_field, a_node, a_red) do { \ (a_node)->a_field.rbn_right_red = (a_type *) ((((intptr_t) \ (a_node)->a_field.rbn_right_red) & ((ssize_t)-2)) \ | ((ssize_t)a_red)); \ } while (0) -#define rbp_red_set(a_type, a_field, a_node) do { \ +#define rbtn_red_set(a_type, a_field, a_node) do { \ (a_node)->a_field.rbn_right_red = (a_type *) (((uintptr_t) \ (a_node)->a_field.rbn_right_red) | ((size_t)1)); \ } while (0) -#define rbp_black_set(a_type, a_field, a_node) do { \ +#define rbtn_black_set(a_type, a_field, a_node) do { \ (a_node)->a_field.rbn_right_red = (a_type *) (((intptr_t) \ (a_node)->a_field.rbn_right_red) & ((ssize_t)-2)); \ } while (0) +#else +/* Right accessors. */ +#define rbtn_right_get(a_type, a_field, a_node) \ + ((a_node)->a_field.rbn_right) +#define rbtn_right_set(a_type, a_field, a_node, a_right) do { \ + (a_node)->a_field.rbn_right = a_right; \ +} while (0) + +/* Color accessors. */ +#define rbtn_red_get(a_type, a_field, a_node) \ + ((a_node)->a_field.rbn_red) +#define rbtn_color_set(a_type, a_field, a_node, a_red) do { \ + (a_node)->a_field.rbn_red = (a_red); \ +} while (0) +#define rbtn_red_set(a_type, a_field, a_node) do { \ + (a_node)->a_field.rbn_red = true; \ +} while (0) +#define rbtn_black_set(a_type, a_field, a_node) do { \ + (a_node)->a_field.rbn_red = false; \ +} while (0) +#endif /* Node initializer. */ -#define rbp_node_new(a_type, a_field, a_tree, a_node) do { \ - rbp_left_set(a_type, a_field, (a_node), &(a_tree)->rbt_nil); \ - rbp_right_set(a_type, a_field, (a_node), &(a_tree)->rbt_nil); \ - rbp_red_set(a_type, a_field, (a_node)); \ +#define rbt_node_new(a_type, a_field, a_rbt, a_node) do { \ + rbtn_left_set(a_type, a_field, (a_node), &(a_rbt)->rbt_nil); \ + rbtn_right_set(a_type, a_field, (a_node), &(a_rbt)->rbt_nil); \ + rbtn_red_set(a_type, a_field, (a_node)); \ } while (0) /* Tree initializer. */ -#define rb_new(a_type, a_field, a_tree) do { \ - (a_tree)->rbt_root = &(a_tree)->rbt_nil; \ - rbp_node_new(a_type, a_field, a_tree, &(a_tree)->rbt_nil); \ - rbp_black_set(a_type, a_field, &(a_tree)->rbt_nil); \ +#define rb_new(a_type, a_field, a_rbt) do { \ + (a_rbt)->rbt_root = &(a_rbt)->rbt_nil; \ + rbt_node_new(a_type, a_field, a_rbt, &(a_rbt)->rbt_nil); \ + rbtn_black_set(a_type, a_field, &(a_rbt)->rbt_nil); \ } while (0) -/* Tree operations. */ -#define rbp_black_height(a_type, a_field, a_tree, r_height) do { \ - a_type *rbp_bh_t; \ - for (rbp_bh_t = (a_tree)->rbt_root, (r_height) = 0; \ - rbp_bh_t != &(a_tree)->rbt_nil; \ - rbp_bh_t = rbp_left_get(a_type, a_field, rbp_bh_t)) { \ - if (rbp_red_get(a_type, a_field, rbp_bh_t) == false) { \ - (r_height)++; \ +/* Internal utility macros. */ +#define rbtn_first(a_type, a_field, a_rbt, a_root, r_node) do { \ + (r_node) = (a_root); \ + if ((r_node) != &(a_rbt)->rbt_nil) { \ + for (; \ + rbtn_left_get(a_type, a_field, (r_node)) != &(a_rbt)->rbt_nil;\ + (r_node) = rbtn_left_get(a_type, a_field, (r_node))) { \ } \ } \ } while (0) -#define rbp_first(a_type, a_field, a_tree, a_root, r_node) do { \ - for ((r_node) = (a_root); \ - rbp_left_get(a_type, a_field, (r_node)) != &(a_tree)->rbt_nil; \ - (r_node) = rbp_left_get(a_type, a_field, (r_node))) { \ +#define rbtn_last(a_type, a_field, a_rbt, a_root, r_node) do { \ + (r_node) = (a_root); \ + if ((r_node) != &(a_rbt)->rbt_nil) { \ + for (; rbtn_right_get(a_type, a_field, (r_node)) != \ + &(a_rbt)->rbt_nil; (r_node) = rbtn_right_get(a_type, a_field, \ + (r_node))) { \ + } \ } \ } while (0) -#define rbp_last(a_type, a_field, a_tree, a_root, r_node) do { \ - for ((r_node) = (a_root); \ - rbp_right_get(a_type, a_field, (r_node)) != &(a_tree)->rbt_nil; \ - (r_node) = rbp_right_get(a_type, a_field, (r_node))) { \ - } \ +#define rbtn_rotate_left(a_type, a_field, a_node, r_node) do { \ + (r_node) = rbtn_right_get(a_type, a_field, (a_node)); \ + rbtn_right_set(a_type, a_field, (a_node), \ + rbtn_left_get(a_type, a_field, (r_node))); \ + rbtn_left_set(a_type, a_field, (r_node), (a_node)); \ } while (0) -#define rbp_next(a_type, a_field, a_cmp, a_tree, a_node, r_node) do { \ - if (rbp_right_get(a_type, a_field, (a_node)) \ - != &(a_tree)->rbt_nil) { \ - rbp_first(a_type, a_field, a_tree, rbp_right_get(a_type, \ - a_field, (a_node)), (r_node)); \ +#define rbtn_rotate_right(a_type, a_field, a_node, r_node) do { \ + (r_node) = rbtn_left_get(a_type, a_field, (a_node)); \ + rbtn_left_set(a_type, a_field, (a_node), \ + rbtn_right_get(a_type, a_field, (r_node))); \ + rbtn_right_set(a_type, a_field, (r_node), (a_node)); \ +} while (0) + +/* + * The rb_proto() macro generates function prototypes that correspond to the + * functions generated by an equivalently parameterized call to rb_gen(). + */ + +#define rb_proto(a_attr, a_prefix, a_rbt_type, a_type) \ +a_attr void \ +a_prefix##new(a_rbt_type *rbtree); \ +a_attr a_type * \ +a_prefix##first(a_rbt_type *rbtree); \ +a_attr a_type * \ +a_prefix##last(a_rbt_type *rbtree); \ +a_attr a_type * \ +a_prefix##next(a_rbt_type *rbtree, a_type *node); \ +a_attr a_type * \ +a_prefix##prev(a_rbt_type *rbtree, a_type *node); \ +a_attr a_type * \ +a_prefix##search(a_rbt_type *rbtree, a_type *key); \ +a_attr a_type * \ +a_prefix##nsearch(a_rbt_type *rbtree, a_type *key); \ +a_attr a_type * \ +a_prefix##psearch(a_rbt_type *rbtree, a_type *key); \ +a_attr void \ +a_prefix##insert(a_rbt_type *rbtree, a_type *node); \ +a_attr void \ +a_prefix##remove(a_rbt_type *rbtree, a_type *node); \ +a_attr a_type * \ +a_prefix##iter(a_rbt_type *rbtree, a_type *start, a_type *(*cb)( \ + a_rbt_type *, a_type *, void *), void *arg); \ +a_attr a_type * \ +a_prefix##reverse_iter(a_rbt_type *rbtree, a_type *start, \ + a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg); + +/* + * The rb_gen() macro generates a type-specific red-black tree implementation, + * based on the above cpp macros. + * + * Arguments: + * + * a_attr : Function attribute for generated functions (ex: static). + * a_prefix : Prefix for generated functions (ex: extree_). + * a_rb_type : Type for red-black tree data structure (ex: extree_t). + * a_type : Type for red-black tree node data structure (ex: + * extree_node_t). + * a_field : Name of red-black tree node linkage (ex: extree_link). + * a_cmp : Node comparison function name, with the following prototype: + * int (a_cmp *)(a_type *a_node, a_type *a_other); + * ^^^^^^ + * or a_key + * Interpretation of comparision function return values: + * -1 : a_node < a_other + * 0 : a_node == a_other + * 1 : a_node > a_other + * In all cases, the a_node or a_key macro argument is the first + * argument to the comparison function, which makes it possible + * to write comparison functions that treat the first argument + * specially. + * + * Assuming the following setup: + * + * typedef struct ex_node_s ex_node_t; + * struct ex_node_s { + * rb_node(ex_node_t) ex_link; + * }; + * typedef rb(ex_node_t) ex_t; + * rb_gen(static, ex_, ex_t, ex_node_t, ex_link, ex_cmp, 1297, 1301) + * + * The following API is generated: + * + * static void + * ex_new(ex_t *extree); + * Description: Initialize a red-black tree structure. + * Args: + * extree: Pointer to an uninitialized red-black tree object. + * + * static ex_node_t * + * ex_first(ex_t *extree); + * static ex_node_t * + * ex_last(ex_t *extree); + * Description: Get the first/last node in extree. + * Args: + * extree: Pointer to an initialized red-black tree object. + * Ret: First/last node in extree, or NULL if extree is empty. + * + * static ex_node_t * + * ex_next(ex_t *extree, ex_node_t *node); + * static ex_node_t * + * ex_prev(ex_t *extree, ex_node_t *node); + * Description: Get node's successor/predecessor. + * Args: + * extree: Pointer to an initialized red-black tree object. + * node : A node in extree. + * Ret: node's successor/predecessor in extree, or NULL if node is + * last/first. + * + * static ex_node_t * + * ex_search(ex_t *extree, ex_node_t *key); + * Description: Search for node that matches key. + * Args: + * extree: Pointer to an initialized red-black tree object. + * key : Search key. + * Ret: Node in extree that matches key, or NULL if no match. + * + * static ex_node_t * + * ex_nsearch(ex_t *extree, ex_node_t *key); + * static ex_node_t * + * ex_psearch(ex_t *extree, ex_node_t *key); + * Description: Search for node that matches key. If no match is found, + * return what would be key's successor/predecessor, were + * key in extree. + * Args: + * extree: Pointer to an initialized red-black tree object. + * key : Search key. + * Ret: Node in extree that matches key, or if no match, hypothetical + * node's successor/predecessor (NULL if no successor/predecessor). + * + * static void + * ex_insert(ex_t *extree, ex_node_t *node); + * Description: Insert node into extree. + * Args: + * extree: Pointer to an initialized red-black tree object. + * node : Node to be inserted into extree. + * + * static void + * ex_remove(ex_t *extree, ex_node_t *node); + * Description: Remove node from extree. + * Args: + * extree: Pointer to an initialized red-black tree object. + * node : Node in extree to be removed. + * + * static ex_node_t * + * ex_iter(ex_t *extree, ex_node_t *start, ex_node_t *(*cb)(ex_t *, + * ex_node_t *, void *), void *arg); + * static ex_node_t * + * ex_reverse_iter(ex_t *extree, ex_node_t *start, ex_node *(*cb)(ex_t *, + * ex_node_t *, void *), void *arg); + * Description: Iterate forward/backward over extree, starting at node. + * If extree is modified, iteration must be immediately + * terminated by the callback function that causes the + * modification. + * Args: + * extree: Pointer to an initialized red-black tree object. + * start : Node at which to start iteration, or NULL to start at + * first/last node. + * cb : Callback function, which is called for each node during + * iteration. Under normal circumstances the callback function + * should return NULL, which causes iteration to continue. If a + * callback function returns non-NULL, iteration is immediately + * terminated and the non-NULL return value is returned by the + * iterator. This is useful for re-starting iteration after + * modifying extree. + * arg : Opaque pointer passed to cb(). + * Ret: NULL if iteration completed, or the non-NULL callback return value + * that caused termination of the iteration. + */ +#define rb_gen(a_attr, a_prefix, a_rbt_type, a_type, a_field, a_cmp) \ +a_attr void \ +a_prefix##new(a_rbt_type *rbtree) { \ + rb_new(a_type, a_field, rbtree); \ +} \ +a_attr a_type * \ +a_prefix##first(a_rbt_type *rbtree) { \ + a_type *ret; \ + rbtn_first(a_type, a_field, rbtree, rbtree->rbt_root, ret); \ + if (ret == &rbtree->rbt_nil) { \ + ret = NULL; \ + } \ + return (ret); \ +} \ +a_attr a_type * \ +a_prefix##last(a_rbt_type *rbtree) { \ + a_type *ret; \ + rbtn_last(a_type, a_field, rbtree, rbtree->rbt_root, ret); \ + if (ret == &rbtree->rbt_nil) { \ + ret = NULL; \ + } \ + return (ret); \ +} \ +a_attr a_type * \ +a_prefix##next(a_rbt_type *rbtree, a_type *node) { \ + a_type *ret; \ + if (rbtn_right_get(a_type, a_field, node) != &rbtree->rbt_nil) { \ + rbtn_first(a_type, a_field, rbtree, rbtn_right_get(a_type, \ + a_field, node), ret); \ } else { \ - a_type *rbp_n_t = (a_tree)->rbt_root; \ - assert(rbp_n_t != &(a_tree)->rbt_nil); \ - (r_node) = &(a_tree)->rbt_nil; \ + a_type *tnode = rbtree->rbt_root; \ + assert(tnode != &rbtree->rbt_nil); \ + ret = &rbtree->rbt_nil; \ while (true) { \ - int rbp_n_cmp = (a_cmp)((a_node), rbp_n_t); \ - if (rbp_n_cmp < 0) { \ - (r_node) = rbp_n_t; \ - rbp_n_t = rbp_left_get(a_type, a_field, rbp_n_t); \ - } else if (rbp_n_cmp > 0) { \ - rbp_n_t = rbp_right_get(a_type, a_field, rbp_n_t); \ + int cmp = (a_cmp)(node, tnode); \ + if (cmp < 0) { \ + ret = tnode; \ + tnode = rbtn_left_get(a_type, a_field, tnode); \ + } else if (cmp > 0) { \ + tnode = rbtn_right_get(a_type, a_field, tnode); \ } else { \ break; \ } \ - assert(rbp_n_t != &(a_tree)->rbt_nil); \ + assert(tnode != &rbtree->rbt_nil); \ } \ } \ -} while (0) - -#define rbp_prev(a_type, a_field, a_cmp, a_tree, a_node, r_node) do { \ - if (rbp_left_get(a_type, a_field, (a_node)) != &(a_tree)->rbt_nil) {\ - rbp_last(a_type, a_field, a_tree, rbp_left_get(a_type, \ - a_field, (a_node)), (r_node)); \ + if (ret == &rbtree->rbt_nil) { \ + ret = (NULL); \ + } \ + return (ret); \ +} \ +a_attr a_type * \ +a_prefix##prev(a_rbt_type *rbtree, a_type *node) { \ + a_type *ret; \ + if (rbtn_left_get(a_type, a_field, node) != &rbtree->rbt_nil) { \ + rbtn_last(a_type, a_field, rbtree, rbtn_left_get(a_type, \ + a_field, node), ret); \ } else { \ - a_type *rbp_p_t = (a_tree)->rbt_root; \ - assert(rbp_p_t != &(a_tree)->rbt_nil); \ - (r_node) = &(a_tree)->rbt_nil; \ + a_type *tnode = rbtree->rbt_root; \ + assert(tnode != &rbtree->rbt_nil); \ + ret = &rbtree->rbt_nil; \ while (true) { \ - int rbp_p_cmp = (a_cmp)((a_node), rbp_p_t); \ - if (rbp_p_cmp < 0) { \ - rbp_p_t = rbp_left_get(a_type, a_field, rbp_p_t); \ - } else if (rbp_p_cmp > 0) { \ - (r_node) = rbp_p_t; \ - rbp_p_t = rbp_right_get(a_type, a_field, rbp_p_t); \ + int cmp = (a_cmp)(node, tnode); \ + if (cmp < 0) { \ + tnode = rbtn_left_get(a_type, a_field, tnode); \ + } else if (cmp > 0) { \ + ret = tnode; \ + tnode = rbtn_right_get(a_type, a_field, tnode); \ } else { \ break; \ } \ - assert(rbp_p_t != &(a_tree)->rbt_nil); \ + assert(tnode != &rbtree->rbt_nil); \ } \ } \ -} while (0) - -#define rb_first(a_type, a_field, a_tree, r_node) do { \ - rbp_first(a_type, a_field, a_tree, (a_tree)->rbt_root, (r_node)); \ - if ((r_node) == &(a_tree)->rbt_nil) { \ - (r_node) = NULL; \ - } \ -} while (0) - -#define rb_last(a_type, a_field, a_tree, r_node) do { \ - rbp_last(a_type, a_field, a_tree, (a_tree)->rbt_root, r_node); \ - if ((r_node) == &(a_tree)->rbt_nil) { \ - (r_node) = NULL; \ + if (ret == &rbtree->rbt_nil) { \ + ret = (NULL); \ } \ -} while (0) - -#define rb_next(a_type, a_field, a_cmp, a_tree, a_node, r_node) do { \ - rbp_next(a_type, a_field, a_cmp, a_tree, (a_node), (r_node)); \ - if ((r_node) == &(a_tree)->rbt_nil) { \ - (r_node) = NULL; \ - } \ -} while (0) - -#define rb_prev(a_type, a_field, a_cmp, a_tree, a_node, r_node) do { \ - rbp_prev(a_type, a_field, a_cmp, a_tree, (a_node), (r_node)); \ - if ((r_node) == &(a_tree)->rbt_nil) { \ - (r_node) = NULL; \ - } \ -} while (0) - -#define rb_search(a_type, a_field, a_cmp, a_tree, a_key, r_node) do { \ - int rbp_se_cmp; \ - (r_node) = (a_tree)->rbt_root; \ - while ((r_node) != &(a_tree)->rbt_nil \ - && (rbp_se_cmp = (a_cmp)((a_key), (r_node))) != 0) { \ - if (rbp_se_cmp < 0) { \ - (r_node) = rbp_left_get(a_type, a_field, (r_node)); \ + return (ret); \ +} \ +a_attr a_type * \ +a_prefix##search(a_rbt_type *rbtree, a_type *key) { \ + a_type *ret; \ + int cmp; \ + ret = rbtree->rbt_root; \ + while (ret != &rbtree->rbt_nil \ + && (cmp = (a_cmp)(key, ret)) != 0) { \ + if (cmp < 0) { \ + ret = rbtn_left_get(a_type, a_field, ret); \ } else { \ - (r_node) = rbp_right_get(a_type, a_field, (r_node)); \ + ret = rbtn_right_get(a_type, a_field, ret); \ } \ } \ - if ((r_node) == &(a_tree)->rbt_nil) { \ - (r_node) = NULL; \ + if (ret == &rbtree->rbt_nil) { \ + ret = (NULL); \ } \ -} while (0) - -/* - * Find a match if it exists. Otherwise, find the next greater node, if one - * exists. - */ -#define rb_nsearch(a_type, a_field, a_cmp, a_tree, a_key, r_node) do { \ - a_type *rbp_ns_t = (a_tree)->rbt_root; \ - (r_node) = NULL; \ - while (rbp_ns_t != &(a_tree)->rbt_nil) { \ - int rbp_ns_cmp = (a_cmp)((a_key), rbp_ns_t); \ - if (rbp_ns_cmp < 0) { \ - (r_node) = rbp_ns_t; \ - rbp_ns_t = rbp_left_get(a_type, a_field, rbp_ns_t); \ - } else if (rbp_ns_cmp > 0) { \ - rbp_ns_t = rbp_right_get(a_type, a_field, rbp_ns_t); \ + return (ret); \ +} \ +a_attr a_type * \ +a_prefix##nsearch(a_rbt_type *rbtree, a_type *key) { \ + a_type *ret; \ + a_type *tnode = rbtree->rbt_root; \ + ret = &rbtree->rbt_nil; \ + while (tnode != &rbtree->rbt_nil) { \ + int cmp = (a_cmp)(key, tnode); \ + if (cmp < 0) { \ + ret = tnode; \ + tnode = rbtn_left_get(a_type, a_field, tnode); \ + } else if (cmp > 0) { \ + tnode = rbtn_right_get(a_type, a_field, tnode); \ } else { \ - (r_node) = rbp_ns_t; \ + ret = tnode; \ break; \ } \ } \ -} while (0) - -/* - * Find a match if it exists. Otherwise, find the previous lesser node, if one - * exists. - */ -#define rb_psearch(a_type, a_field, a_cmp, a_tree, a_key, r_node) do { \ - a_type *rbp_ps_t = (a_tree)->rbt_root; \ - (r_node) = NULL; \ - while (rbp_ps_t != &(a_tree)->rbt_nil) { \ - int rbp_ps_cmp = (a_cmp)((a_key), rbp_ps_t); \ - if (rbp_ps_cmp < 0) { \ - rbp_ps_t = rbp_left_get(a_type, a_field, rbp_ps_t); \ - } else if (rbp_ps_cmp > 0) { \ - (r_node) = rbp_ps_t; \ - rbp_ps_t = rbp_right_get(a_type, a_field, rbp_ps_t); \ + if (ret == &rbtree->rbt_nil) { \ + ret = (NULL); \ + } \ + return (ret); \ +} \ +a_attr a_type * \ +a_prefix##psearch(a_rbt_type *rbtree, a_type *key) { \ + a_type *ret; \ + a_type *tnode = rbtree->rbt_root; \ + ret = &rbtree->rbt_nil; \ + while (tnode != &rbtree->rbt_nil) { \ + int cmp = (a_cmp)(key, tnode); \ + if (cmp < 0) { \ + tnode = rbtn_left_get(a_type, a_field, tnode); \ + } else if (cmp > 0) { \ + ret = tnode; \ + tnode = rbtn_right_get(a_type, a_field, tnode); \ } else { \ - (r_node) = rbp_ps_t; \ + ret = tnode; \ break; \ } \ } \ -} while (0) - -#define rbp_rotate_left(a_type, a_field, a_node, r_node) do { \ - (r_node) = rbp_right_get(a_type, a_field, (a_node)); \ - rbp_right_set(a_type, a_field, (a_node), \ - rbp_left_get(a_type, a_field, (r_node))); \ - rbp_left_set(a_type, a_field, (r_node), (a_node)); \ -} while (0) - -#define rbp_rotate_right(a_type, a_field, a_node, r_node) do { \ - (r_node) = rbp_left_get(a_type, a_field, (a_node)); \ - rbp_left_set(a_type, a_field, (a_node), \ - rbp_right_get(a_type, a_field, (r_node))); \ - rbp_right_set(a_type, a_field, (r_node), (a_node)); \ -} while (0) - -#define rbp_lean_left(a_type, a_field, a_node, r_node) do { \ - bool rbp_ll_red; \ - rbp_rotate_left(a_type, a_field, (a_node), (r_node)); \ - rbp_ll_red = rbp_red_get(a_type, a_field, (a_node)); \ - rbp_color_set(a_type, a_field, (r_node), rbp_ll_red); \ - rbp_red_set(a_type, a_field, (a_node)); \ -} while (0) - -#define rbp_lean_right(a_type, a_field, a_node, r_node) do { \ - bool rbp_lr_red; \ - rbp_rotate_right(a_type, a_field, (a_node), (r_node)); \ - rbp_lr_red = rbp_red_get(a_type, a_field, (a_node)); \ - rbp_color_set(a_type, a_field, (r_node), rbp_lr_red); \ - rbp_red_set(a_type, a_field, (a_node)); \ -} while (0) - -#define rbp_move_red_left(a_type, a_field, a_node, r_node) do { \ - a_type *rbp_mrl_t, *rbp_mrl_u; \ - rbp_mrl_t = rbp_left_get(a_type, a_field, (a_node)); \ - rbp_red_set(a_type, a_field, rbp_mrl_t); \ - rbp_mrl_t = rbp_right_get(a_type, a_field, (a_node)); \ - rbp_mrl_u = rbp_left_get(a_type, a_field, rbp_mrl_t); \ - if (rbp_red_get(a_type, a_field, rbp_mrl_u)) { \ - rbp_rotate_right(a_type, a_field, rbp_mrl_t, rbp_mrl_u); \ - rbp_right_set(a_type, a_field, (a_node), rbp_mrl_u); \ - rbp_rotate_left(a_type, a_field, (a_node), (r_node)); \ - rbp_mrl_t = rbp_right_get(a_type, a_field, (a_node)); \ - if (rbp_red_get(a_type, a_field, rbp_mrl_t)) { \ - rbp_black_set(a_type, a_field, rbp_mrl_t); \ - rbp_red_set(a_type, a_field, (a_node)); \ - rbp_rotate_left(a_type, a_field, (a_node), rbp_mrl_t); \ - rbp_left_set(a_type, a_field, (r_node), rbp_mrl_t); \ - } else { \ - rbp_black_set(a_type, a_field, (a_node)); \ - } \ - } else { \ - rbp_red_set(a_type, a_field, (a_node)); \ - rbp_rotate_left(a_type, a_field, (a_node), (r_node)); \ + if (ret == &rbtree->rbt_nil) { \ + ret = (NULL); \ } \ -} while (0) - -#define rbp_move_red_right(a_type, a_field, a_node, r_node) do { \ - a_type *rbp_mrr_t; \ - rbp_mrr_t = rbp_left_get(a_type, a_field, (a_node)); \ - if (rbp_red_get(a_type, a_field, rbp_mrr_t)) { \ - a_type *rbp_mrr_u, *rbp_mrr_v; \ - rbp_mrr_u = rbp_right_get(a_type, a_field, rbp_mrr_t); \ - rbp_mrr_v = rbp_left_get(a_type, a_field, rbp_mrr_u); \ - if (rbp_red_get(a_type, a_field, rbp_mrr_v)) { \ - rbp_color_set(a_type, a_field, rbp_mrr_u, \ - rbp_red_get(a_type, a_field, (a_node))); \ - rbp_black_set(a_type, a_field, rbp_mrr_v); \ - rbp_rotate_left(a_type, a_field, rbp_mrr_t, rbp_mrr_u); \ - rbp_left_set(a_type, a_field, (a_node), rbp_mrr_u); \ - rbp_rotate_right(a_type, a_field, (a_node), (r_node)); \ - rbp_rotate_left(a_type, a_field, (a_node), rbp_mrr_t); \ - rbp_right_set(a_type, a_field, (r_node), rbp_mrr_t); \ - } else { \ - rbp_color_set(a_type, a_field, rbp_mrr_t, \ - rbp_red_get(a_type, a_field, (a_node))); \ - rbp_red_set(a_type, a_field, rbp_mrr_u); \ - rbp_rotate_right(a_type, a_field, (a_node), (r_node)); \ - rbp_rotate_left(a_type, a_field, (a_node), rbp_mrr_t); \ - rbp_right_set(a_type, a_field, (r_node), rbp_mrr_t); \ - } \ - rbp_red_set(a_type, a_field, (a_node)); \ - } else { \ - rbp_red_set(a_type, a_field, rbp_mrr_t); \ - rbp_mrr_t = rbp_left_get(a_type, a_field, rbp_mrr_t); \ - if (rbp_red_get(a_type, a_field, rbp_mrr_t)) { \ - rbp_black_set(a_type, a_field, rbp_mrr_t); \ - rbp_rotate_right(a_type, a_field, (a_node), (r_node)); \ - rbp_rotate_left(a_type, a_field, (a_node), rbp_mrr_t); \ - rbp_right_set(a_type, a_field, (r_node), rbp_mrr_t); \ + return (ret); \ +} \ +a_attr void \ +a_prefix##insert(a_rbt_type *rbtree, a_type *node) { \ + struct { \ + a_type *node; \ + int cmp; \ + } path[sizeof(void *) << 4], *pathp; \ + rbt_node_new(a_type, a_field, rbtree, node); \ + /* Wind. */ \ + path->node = rbtree->rbt_root; \ + for (pathp = path; pathp->node != &rbtree->rbt_nil; pathp++) { \ + int cmp = pathp->cmp = a_cmp(node, pathp->node); \ + assert(cmp != 0); \ + if (cmp < 0) { \ + pathp[1].node = rbtn_left_get(a_type, a_field, \ + pathp->node); \ } else { \ - rbp_rotate_left(a_type, a_field, (a_node), (r_node)); \ + pathp[1].node = rbtn_right_get(a_type, a_field, \ + pathp->node); \ } \ } \ -} while (0) - -#define rb_insert(a_type, a_field, a_cmp, a_tree, a_node) do { \ - a_type rbp_i_s; \ - a_type *rbp_i_g, *rbp_i_p, *rbp_i_c, *rbp_i_t, *rbp_i_u; \ - int rbp_i_cmp = 0; \ - rbp_i_g = &(a_tree)->rbt_nil; \ - rbp_left_set(a_type, a_field, &rbp_i_s, (a_tree)->rbt_root); \ - rbp_right_set(a_type, a_field, &rbp_i_s, &(a_tree)->rbt_nil); \ - rbp_black_set(a_type, a_field, &rbp_i_s); \ - rbp_i_p = &rbp_i_s; \ - rbp_i_c = (a_tree)->rbt_root; \ - /* Iteratively search down the tree for the insertion point, */\ - /* splitting 4-nodes as they are encountered. At the end of each */\ - /* iteration, rbp_i_g->rbp_i_p->rbp_i_c is a 3-level path down */\ - /* the tree, assuming a sufficiently deep tree. */\ - while (rbp_i_c != &(a_tree)->rbt_nil) { \ - rbp_i_t = rbp_left_get(a_type, a_field, rbp_i_c); \ - rbp_i_u = rbp_left_get(a_type, a_field, rbp_i_t); \ - if (rbp_red_get(a_type, a_field, rbp_i_t) \ - && rbp_red_get(a_type, a_field, rbp_i_u)) { \ - /* rbp_i_c is the top of a logical 4-node, so split it. */\ - /* This iteration does not move down the tree, due to the */\ - /* disruptiveness of node splitting. */\ - /* */\ - /* Rotate right. */\ - rbp_rotate_right(a_type, a_field, rbp_i_c, rbp_i_t); \ - /* Pass red links up one level. */\ - rbp_i_u = rbp_left_get(a_type, a_field, rbp_i_t); \ - rbp_black_set(a_type, a_field, rbp_i_u); \ - if (rbp_left_get(a_type, a_field, rbp_i_p) == rbp_i_c) { \ - rbp_left_set(a_type, a_field, rbp_i_p, rbp_i_t); \ - rbp_i_c = rbp_i_t; \ - } else { \ - /* rbp_i_c was the right child of rbp_i_p, so rotate */\ - /* left in order to maintain the left-leaning */\ - /* invariant. */\ - assert(rbp_right_get(a_type, a_field, rbp_i_p) \ - == rbp_i_c); \ - rbp_right_set(a_type, a_field, rbp_i_p, rbp_i_t); \ - rbp_lean_left(a_type, a_field, rbp_i_p, rbp_i_u); \ - if (rbp_left_get(a_type, a_field, rbp_i_g) == rbp_i_p) {\ - rbp_left_set(a_type, a_field, rbp_i_g, rbp_i_u); \ - } else { \ - assert(rbp_right_get(a_type, a_field, rbp_i_g) \ - == rbp_i_p); \ - rbp_right_set(a_type, a_field, rbp_i_g, rbp_i_u); \ + pathp->node = node; \ + /* Unwind. */ \ + for (pathp--; (uintptr_t)pathp >= (uintptr_t)path; pathp--) { \ + a_type *cnode = pathp->node; \ + if (pathp->cmp < 0) { \ + a_type *left = pathp[1].node; \ + rbtn_left_set(a_type, a_field, cnode, left); \ + if (rbtn_red_get(a_type, a_field, left)) { \ + a_type *leftleft = rbtn_left_get(a_type, a_field, left);\ + if (rbtn_red_get(a_type, a_field, leftleft)) { \ + /* Fix up 4-node. */ \ + a_type *tnode; \ + rbtn_black_set(a_type, a_field, leftleft); \ + rbtn_rotate_right(a_type, a_field, cnode, tnode); \ + cnode = tnode; \ } \ - rbp_i_p = rbp_i_u; \ - rbp_i_cmp = (a_cmp)((a_node), rbp_i_p); \ - if (rbp_i_cmp < 0) { \ - rbp_i_c = rbp_left_get(a_type, a_field, rbp_i_p); \ + } else { \ + return; \ + } \ + } else { \ + a_type *right = pathp[1].node; \ + rbtn_right_set(a_type, a_field, cnode, right); \ + if (rbtn_red_get(a_type, a_field, right)) { \ + a_type *left = rbtn_left_get(a_type, a_field, cnode); \ + if (rbtn_red_get(a_type, a_field, left)) { \ + /* Split 4-node. */ \ + rbtn_black_set(a_type, a_field, left); \ + rbtn_black_set(a_type, a_field, right); \ + rbtn_red_set(a_type, a_field, cnode); \ } else { \ - assert(rbp_i_cmp > 0); \ - rbp_i_c = rbp_right_get(a_type, a_field, rbp_i_p); \ + /* Lean left. */ \ + a_type *tnode; \ + bool tred = rbtn_red_get(a_type, a_field, cnode); \ + rbtn_rotate_left(a_type, a_field, cnode, tnode); \ + rbtn_color_set(a_type, a_field, tnode, tred); \ + rbtn_red_set(a_type, a_field, cnode); \ + cnode = tnode; \ } \ - continue; \ + } else { \ + return; \ } \ } \ - rbp_i_g = rbp_i_p; \ - rbp_i_p = rbp_i_c; \ - rbp_i_cmp = (a_cmp)((a_node), rbp_i_c); \ - if (rbp_i_cmp < 0) { \ - rbp_i_c = rbp_left_get(a_type, a_field, rbp_i_c); \ - } else { \ - assert(rbp_i_cmp > 0); \ - rbp_i_c = rbp_right_get(a_type, a_field, rbp_i_c); \ - } \ + pathp->node = cnode; \ } \ - /* rbp_i_p now refers to the node under which to insert. */\ - rbp_node_new(a_type, a_field, a_tree, (a_node)); \ - if (rbp_i_cmp > 0) { \ - rbp_right_set(a_type, a_field, rbp_i_p, (a_node)); \ - rbp_lean_left(a_type, a_field, rbp_i_p, rbp_i_t); \ - if (rbp_left_get(a_type, a_field, rbp_i_g) == rbp_i_p) { \ - rbp_left_set(a_type, a_field, rbp_i_g, rbp_i_t); \ - } else if (rbp_right_get(a_type, a_field, rbp_i_g) == rbp_i_p) {\ - rbp_right_set(a_type, a_field, rbp_i_g, rbp_i_t); \ + /* Set root, and make it black. */ \ + rbtree->rbt_root = path->node; \ + rbtn_black_set(a_type, a_field, rbtree->rbt_root); \ +} \ +a_attr void \ +a_prefix##remove(a_rbt_type *rbtree, a_type *node) { \ + struct { \ + a_type *node; \ + int cmp; \ + } *pathp, *nodep, path[sizeof(void *) << 4]; \ + /* Wind. */ \ + nodep = NULL; /* Silence compiler warning. */ \ + path->node = rbtree->rbt_root; \ + for (pathp = path; pathp->node != &rbtree->rbt_nil; pathp++) { \ + int cmp = pathp->cmp = a_cmp(node, pathp->node); \ + if (cmp < 0) { \ + pathp[1].node = rbtn_left_get(a_type, a_field, \ + pathp->node); \ + } else { \ + pathp[1].node = rbtn_right_get(a_type, a_field, \ + pathp->node); \ + if (cmp == 0) { \ + /* Find node's successor, in preparation for swap. */ \ + pathp->cmp = 1; \ + nodep = pathp; \ + for (pathp++; pathp->node != &rbtree->rbt_nil; \ + pathp++) { \ + pathp->cmp = -1; \ + pathp[1].node = rbtn_left_get(a_type, a_field, \ + pathp->node); \ + } \ + break; \ + } \ } \ - } else { \ - rbp_left_set(a_type, a_field, rbp_i_p, (a_node)); \ } \ - /* Update the root and make sure that it is black. */\ - (a_tree)->rbt_root = rbp_left_get(a_type, a_field, &rbp_i_s); \ - rbp_black_set(a_type, a_field, (a_tree)->rbt_root); \ -} while (0) - -#define rb_remove(a_type, a_field, a_cmp, a_tree, a_node) do { \ - a_type rbp_r_s; \ - a_type *rbp_r_p, *rbp_r_c, *rbp_r_xp, *rbp_r_t, *rbp_r_u; \ - int rbp_r_cmp; \ - rbp_left_set(a_type, a_field, &rbp_r_s, (a_tree)->rbt_root); \ - rbp_right_set(a_type, a_field, &rbp_r_s, &(a_tree)->rbt_nil); \ - rbp_black_set(a_type, a_field, &rbp_r_s); \ - rbp_r_p = &rbp_r_s; \ - rbp_r_c = (a_tree)->rbt_root; \ - rbp_r_xp = &(a_tree)->rbt_nil; \ - /* Iterate down the tree, but always transform 2-nodes to 3- or */\ - /* 4-nodes in order to maintain the invariant that the current */\ - /* node is not a 2-node. This allows simple deletion once a leaf */\ - /* is reached. Handle the root specially though, since there may */\ - /* be no way to convert it from a 2-node to a 3-node. */\ - rbp_r_cmp = (a_cmp)((a_node), rbp_r_c); \ - if (rbp_r_cmp < 0) { \ - rbp_r_t = rbp_left_get(a_type, a_field, rbp_r_c); \ - rbp_r_u = rbp_left_get(a_type, a_field, rbp_r_t); \ - if (rbp_red_get(a_type, a_field, rbp_r_t) == false \ - && rbp_red_get(a_type, a_field, rbp_r_u) == false) { \ - /* Apply standard transform to prepare for left move. */\ - rbp_move_red_left(a_type, a_field, rbp_r_c, rbp_r_t); \ - rbp_black_set(a_type, a_field, rbp_r_t); \ - rbp_left_set(a_type, a_field, rbp_r_p, rbp_r_t); \ - rbp_r_c = rbp_r_t; \ + assert(nodep->node == node); \ + pathp--; \ + if (pathp->node != node) { \ + /* Swap node with its successor. */ \ + bool tred = rbtn_red_get(a_type, a_field, pathp->node); \ + rbtn_color_set(a_type, a_field, pathp->node, \ + rbtn_red_get(a_type, a_field, node)); \ + rbtn_left_set(a_type, a_field, pathp->node, \ + rbtn_left_get(a_type, a_field, node)); \ + /* If node's successor is its right child, the following code */\ + /* will do the wrong thing for the right child pointer. */\ + /* However, it doesn't matter, because the pointer will be */\ + /* properly set when the successor is pruned. */\ + rbtn_right_set(a_type, a_field, pathp->node, \ + rbtn_right_get(a_type, a_field, node)); \ + rbtn_color_set(a_type, a_field, node, tred); \ + /* The pruned leaf node's child pointers are never accessed */\ + /* again, so don't bother setting them to nil. */\ + nodep->node = pathp->node; \ + pathp->node = node; \ + if (nodep == path) { \ + rbtree->rbt_root = nodep->node; \ } else { \ - /* Move left. */\ - rbp_r_p = rbp_r_c; \ - rbp_r_c = rbp_left_get(a_type, a_field, rbp_r_c); \ + if (nodep[-1].cmp < 0) { \ + rbtn_left_set(a_type, a_field, nodep[-1].node, \ + nodep->node); \ + } else { \ + rbtn_right_set(a_type, a_field, nodep[-1].node, \ + nodep->node); \ + } \ } \ } else { \ - if (rbp_r_cmp == 0) { \ - assert((a_node) == rbp_r_c); \ - if (rbp_right_get(a_type, a_field, rbp_r_c) \ - == &(a_tree)->rbt_nil) { \ - /* Delete root node (which is also a leaf node). */\ - if (rbp_left_get(a_type, a_field, rbp_r_c) \ - != &(a_tree)->rbt_nil) { \ - rbp_lean_right(a_type, a_field, rbp_r_c, rbp_r_t); \ - rbp_right_set(a_type, a_field, rbp_r_t, \ - &(a_tree)->rbt_nil); \ + a_type *left = rbtn_left_get(a_type, a_field, node); \ + if (left != &rbtree->rbt_nil) { \ + /* node has no successor, but it has a left child. */\ + /* Splice node out, without losing the left child. */\ + assert(rbtn_red_get(a_type, a_field, node) == false); \ + assert(rbtn_red_get(a_type, a_field, left)); \ + rbtn_black_set(a_type, a_field, left); \ + if (pathp == path) { \ + rbtree->rbt_root = left; \ + } else { \ + if (pathp[-1].cmp < 0) { \ + rbtn_left_set(a_type, a_field, pathp[-1].node, \ + left); \ } else { \ - rbp_r_t = &(a_tree)->rbt_nil; \ + rbtn_right_set(a_type, a_field, pathp[-1].node, \ + left); \ } \ - rbp_left_set(a_type, a_field, rbp_r_p, rbp_r_t); \ - } else { \ - /* This is the node we want to delete, but we will */\ - /* instead swap it with its successor and delete the */\ - /* successor. Record enough information to do the */\ - /* swap later. rbp_r_xp is the a_node's parent. */\ - rbp_r_xp = rbp_r_p; \ - rbp_r_cmp = 1; /* Note that deletion is incomplete. */\ } \ + return; \ + } else if (pathp == path) { \ + /* The tree only contained one node. */ \ + rbtree->rbt_root = &rbtree->rbt_nil; \ + return; \ } \ - if (rbp_r_cmp == 1) { \ - if (rbp_red_get(a_type, a_field, rbp_left_get(a_type, \ - a_field, rbp_right_get(a_type, a_field, rbp_r_c))) \ - == false) { \ - rbp_r_t = rbp_left_get(a_type, a_field, rbp_r_c); \ - if (rbp_red_get(a_type, a_field, rbp_r_t)) { \ - /* Standard transform. */\ - rbp_move_red_right(a_type, a_field, rbp_r_c, \ - rbp_r_t); \ + } \ + if (rbtn_red_get(a_type, a_field, pathp->node)) { \ + /* Prune red node, which requires no fixup. */ \ + assert(pathp[-1].cmp < 0); \ + rbtn_left_set(a_type, a_field, pathp[-1].node, \ + &rbtree->rbt_nil); \ + return; \ + } \ + /* The node to be pruned is black, so unwind until balance is */\ + /* restored. */\ + pathp->node = &rbtree->rbt_nil; \ + for (pathp--; (uintptr_t)pathp >= (uintptr_t)path; pathp--) { \ + assert(pathp->cmp != 0); \ + if (pathp->cmp < 0) { \ + rbtn_left_set(a_type, a_field, pathp->node, \ + pathp[1].node); \ + assert(rbtn_red_get(a_type, a_field, pathp[1].node) \ + == false); \ + if (rbtn_red_get(a_type, a_field, pathp->node)) { \ + a_type *right = rbtn_right_get(a_type, a_field, \ + pathp->node); \ + a_type *rightleft = rbtn_left_get(a_type, a_field, \ + right); \ + a_type *tnode; \ + if (rbtn_red_get(a_type, a_field, rightleft)) { \ + /* In the following diagrams, ||, //, and \\ */\ + /* indicate the path to the removed node. */\ + /* */\ + /* || */\ + /* pathp(r) */\ + /* // \ */\ + /* (b) (b) */\ + /* / */\ + /* (r) */\ + /* */\ + rbtn_black_set(a_type, a_field, pathp->node); \ + rbtn_rotate_right(a_type, a_field, right, tnode); \ + rbtn_right_set(a_type, a_field, pathp->node, tnode);\ + rbtn_rotate_left(a_type, a_field, pathp->node, \ + tnode); \ } else { \ - /* Root-specific transform. */\ - rbp_red_set(a_type, a_field, rbp_r_c); \ - rbp_r_u = rbp_left_get(a_type, a_field, rbp_r_t); \ - if (rbp_red_get(a_type, a_field, rbp_r_u)) { \ - rbp_black_set(a_type, a_field, rbp_r_u); \ - rbp_rotate_right(a_type, a_field, rbp_r_c, \ - rbp_r_t); \ - rbp_rotate_left(a_type, a_field, rbp_r_c, \ - rbp_r_u); \ - rbp_right_set(a_type, a_field, rbp_r_t, \ - rbp_r_u); \ - } else { \ - rbp_red_set(a_type, a_field, rbp_r_t); \ - rbp_rotate_left(a_type, a_field, rbp_r_c, \ - rbp_r_t); \ - } \ + /* || */\ + /* pathp(r) */\ + /* // \ */\ + /* (b) (b) */\ + /* / */\ + /* (b) */\ + /* */\ + rbtn_rotate_left(a_type, a_field, pathp->node, \ + tnode); \ + } \ + /* Balance restored, but rotation modified subtree */\ + /* root. */\ + assert((uintptr_t)pathp > (uintptr_t)path); \ + if (pathp[-1].cmp < 0) { \ + rbtn_left_set(a_type, a_field, pathp[-1].node, \ + tnode); \ + } else { \ + rbtn_right_set(a_type, a_field, pathp[-1].node, \ + tnode); \ } \ - rbp_left_set(a_type, a_field, rbp_r_p, rbp_r_t); \ - rbp_r_c = rbp_r_t; \ + return; \ } else { \ - /* Move right. */\ - rbp_r_p = rbp_r_c; \ - rbp_r_c = rbp_right_get(a_type, a_field, rbp_r_c); \ - } \ - } \ - } \ - if (rbp_r_cmp != 0) { \ - while (true) { \ - assert(rbp_r_p != &(a_tree)->rbt_nil); \ - rbp_r_cmp = (a_cmp)((a_node), rbp_r_c); \ - if (rbp_r_cmp < 0) { \ - rbp_r_t = rbp_left_get(a_type, a_field, rbp_r_c); \ - if (rbp_r_t == &(a_tree)->rbt_nil) { \ - /* rbp_r_c now refers to the successor node to */\ - /* relocate, and rbp_r_xp/a_node refer to the */\ - /* context for the relocation. */\ - if (rbp_left_get(a_type, a_field, rbp_r_xp) \ - == (a_node)) { \ - rbp_left_set(a_type, a_field, rbp_r_xp, \ - rbp_r_c); \ + a_type *right = rbtn_right_get(a_type, a_field, \ + pathp->node); \ + a_type *rightleft = rbtn_left_get(a_type, a_field, \ + right); \ + if (rbtn_red_get(a_type, a_field, rightleft)) { \ + /* || */\ + /* pathp(b) */\ + /* // \ */\ + /* (b) (b) */\ + /* / */\ + /* (r) */\ + a_type *tnode; \ + rbtn_black_set(a_type, a_field, rightleft); \ + rbtn_rotate_right(a_type, a_field, right, tnode); \ + rbtn_right_set(a_type, a_field, pathp->node, tnode);\ + rbtn_rotate_left(a_type, a_field, pathp->node, \ + tnode); \ + /* Balance restored, but rotation modified */\ + /* subree root, which may actually be the tree */\ + /* root. */\ + if (pathp == path) { \ + /* Set root. */ \ + rbtree->rbt_root = tnode; \ } else { \ - assert(rbp_right_get(a_type, a_field, \ - rbp_r_xp) == (a_node)); \ - rbp_right_set(a_type, a_field, rbp_r_xp, \ - rbp_r_c); \ + if (pathp[-1].cmp < 0) { \ + rbtn_left_set(a_type, a_field, \ + pathp[-1].node, tnode); \ + } else { \ + rbtn_right_set(a_type, a_field, \ + pathp[-1].node, tnode); \ + } \ } \ - rbp_left_set(a_type, a_field, rbp_r_c, \ - rbp_left_get(a_type, a_field, (a_node))); \ - rbp_right_set(a_type, a_field, rbp_r_c, \ - rbp_right_get(a_type, a_field, (a_node))); \ - rbp_color_set(a_type, a_field, rbp_r_c, \ - rbp_red_get(a_type, a_field, (a_node))); \ - if (rbp_left_get(a_type, a_field, rbp_r_p) \ - == rbp_r_c) { \ - rbp_left_set(a_type, a_field, rbp_r_p, \ - &(a_tree)->rbt_nil); \ + return; \ + } else { \ + /* || */\ + /* pathp(b) */\ + /* // \ */\ + /* (b) (b) */\ + /* / */\ + /* (b) */\ + a_type *tnode; \ + rbtn_red_set(a_type, a_field, pathp->node); \ + rbtn_rotate_left(a_type, a_field, pathp->node, \ + tnode); \ + pathp->node = tnode; \ + } \ + } \ + } else { \ + a_type *left; \ + rbtn_right_set(a_type, a_field, pathp->node, \ + pathp[1].node); \ + left = rbtn_left_get(a_type, a_field, pathp->node); \ + if (rbtn_red_get(a_type, a_field, left)) { \ + a_type *tnode; \ + a_type *leftright = rbtn_right_get(a_type, a_field, \ + left); \ + a_type *leftrightleft = rbtn_left_get(a_type, a_field, \ + leftright); \ + if (rbtn_red_get(a_type, a_field, leftrightleft)) { \ + /* || */\ + /* pathp(b) */\ + /* / \\ */\ + /* (r) (b) */\ + /* \ */\ + /* (b) */\ + /* / */\ + /* (r) */\ + a_type *unode; \ + rbtn_black_set(a_type, a_field, leftrightleft); \ + rbtn_rotate_right(a_type, a_field, pathp->node, \ + unode); \ + rbtn_rotate_right(a_type, a_field, pathp->node, \ + tnode); \ + rbtn_right_set(a_type, a_field, unode, tnode); \ + rbtn_rotate_left(a_type, a_field, unode, tnode); \ + } else { \ + /* || */\ + /* pathp(b) */\ + /* / \\ */\ + /* (r) (b) */\ + /* \ */\ + /* (b) */\ + /* / */\ + /* (b) */\ + assert(leftright != &rbtree->rbt_nil); \ + rbtn_red_set(a_type, a_field, leftright); \ + rbtn_rotate_right(a_type, a_field, pathp->node, \ + tnode); \ + rbtn_black_set(a_type, a_field, tnode); \ + } \ + /* Balance restored, but rotation modified subtree */\ + /* root, which may actually be the tree root. */\ + if (pathp == path) { \ + /* Set root. */ \ + rbtree->rbt_root = tnode; \ + } else { \ + if (pathp[-1].cmp < 0) { \ + rbtn_left_set(a_type, a_field, pathp[-1].node, \ + tnode); \ } else { \ - assert(rbp_right_get(a_type, a_field, rbp_r_p) \ - == rbp_r_c); \ - rbp_right_set(a_type, a_field, rbp_r_p, \ - &(a_tree)->rbt_nil); \ + rbtn_right_set(a_type, a_field, pathp[-1].node, \ + tnode); \ } \ - break; \ } \ - rbp_r_u = rbp_left_get(a_type, a_field, rbp_r_t); \ - if (rbp_red_get(a_type, a_field, rbp_r_t) == false \ - && rbp_red_get(a_type, a_field, rbp_r_u) == false) { \ - rbp_move_red_left(a_type, a_field, rbp_r_c, \ - rbp_r_t); \ - if (rbp_left_get(a_type, a_field, rbp_r_p) \ - == rbp_r_c) { \ - rbp_left_set(a_type, a_field, rbp_r_p, rbp_r_t);\ + return; \ + } else if (rbtn_red_get(a_type, a_field, pathp->node)) { \ + a_type *leftleft = rbtn_left_get(a_type, a_field, left);\ + if (rbtn_red_get(a_type, a_field, leftleft)) { \ + /* || */\ + /* pathp(r) */\ + /* / \\ */\ + /* (b) (b) */\ + /* / */\ + /* (r) */\ + a_type *tnode; \ + rbtn_black_set(a_type, a_field, pathp->node); \ + rbtn_red_set(a_type, a_field, left); \ + rbtn_black_set(a_type, a_field, leftleft); \ + rbtn_rotate_right(a_type, a_field, pathp->node, \ + tnode); \ + /* Balance restored, but rotation modified */\ + /* subtree root. */\ + assert((uintptr_t)pathp > (uintptr_t)path); \ + if (pathp[-1].cmp < 0) { \ + rbtn_left_set(a_type, a_field, pathp[-1].node, \ + tnode); \ } else { \ - rbp_right_set(a_type, a_field, rbp_r_p, \ - rbp_r_t); \ + rbtn_right_set(a_type, a_field, pathp[-1].node, \ + tnode); \ } \ - rbp_r_c = rbp_r_t; \ + return; \ } else { \ - rbp_r_p = rbp_r_c; \ - rbp_r_c = rbp_left_get(a_type, a_field, rbp_r_c); \ + /* || */\ + /* pathp(r) */\ + /* / \\ */\ + /* (b) (b) */\ + /* / */\ + /* (b) */\ + rbtn_red_set(a_type, a_field, left); \ + rbtn_black_set(a_type, a_field, pathp->node); \ + /* Balance restored. */ \ + return; \ } \ } else { \ - /* Check whether to delete this node (it has to be */\ - /* the correct node and a leaf node). */\ - if (rbp_r_cmp == 0) { \ - assert((a_node) == rbp_r_c); \ - if (rbp_right_get(a_type, a_field, rbp_r_c) \ - == &(a_tree)->rbt_nil) { \ - /* Delete leaf node. */\ - if (rbp_left_get(a_type, a_field, rbp_r_c) \ - != &(a_tree)->rbt_nil) { \ - rbp_lean_right(a_type, a_field, rbp_r_c, \ - rbp_r_t); \ - rbp_right_set(a_type, a_field, rbp_r_t, \ - &(a_tree)->rbt_nil); \ - } else { \ - rbp_r_t = &(a_tree)->rbt_nil; \ - } \ - if (rbp_left_get(a_type, a_field, rbp_r_p) \ - == rbp_r_c) { \ - rbp_left_set(a_type, a_field, rbp_r_p, \ - rbp_r_t); \ + a_type *leftleft = rbtn_left_get(a_type, a_field, left);\ + if (rbtn_red_get(a_type, a_field, leftleft)) { \ + /* || */\ + /* pathp(b) */\ + /* / \\ */\ + /* (b) (b) */\ + /* / */\ + /* (r) */\ + a_type *tnode; \ + rbtn_black_set(a_type, a_field, leftleft); \ + rbtn_rotate_right(a_type, a_field, pathp->node, \ + tnode); \ + /* Balance restored, but rotation modified */\ + /* subtree root, which may actually be the tree */\ + /* root. */\ + if (pathp == path) { \ + /* Set root. */ \ + rbtree->rbt_root = tnode; \ + } else { \ + if (pathp[-1].cmp < 0) { \ + rbtn_left_set(a_type, a_field, \ + pathp[-1].node, tnode); \ } else { \ - rbp_right_set(a_type, a_field, rbp_r_p, \ - rbp_r_t); \ + rbtn_right_set(a_type, a_field, \ + pathp[-1].node, tnode); \ } \ - break; \ - } else { \ - /* This is the node we want to delete, but we */\ - /* will instead swap it with its successor */\ - /* and delete the successor. Record enough */\ - /* information to do the swap later. */\ - /* rbp_r_xp is a_node's parent. */\ - rbp_r_xp = rbp_r_p; \ } \ - } \ - rbp_r_t = rbp_right_get(a_type, a_field, rbp_r_c); \ - rbp_r_u = rbp_left_get(a_type, a_field, rbp_r_t); \ - if (rbp_red_get(a_type, a_field, rbp_r_u) == false) { \ - rbp_move_red_right(a_type, a_field, rbp_r_c, \ - rbp_r_t); \ - if (rbp_left_get(a_type, a_field, rbp_r_p) \ - == rbp_r_c) { \ - rbp_left_set(a_type, a_field, rbp_r_p, rbp_r_t);\ - } else { \ - rbp_right_set(a_type, a_field, rbp_r_p, \ - rbp_r_t); \ - } \ - rbp_r_c = rbp_r_t; \ + return; \ } else { \ - rbp_r_p = rbp_r_c; \ - rbp_r_c = rbp_right_get(a_type, a_field, rbp_r_c); \ + /* || */\ + /* pathp(b) */\ + /* / \\ */\ + /* (b) (b) */\ + /* / */\ + /* (b) */\ + rbtn_red_set(a_type, a_field, left); \ } \ } \ } \ } \ - /* Update root. */\ - (a_tree)->rbt_root = rbp_left_get(a_type, a_field, &rbp_r_s); \ -} while (0) - -/* - * The rb_wrap() macro provides a convenient way to wrap functions around the - * cpp macros. The main benefits of wrapping are that 1) repeated macro - * expansion can cause code bloat, especially for rb_{insert,remove)(), and - * 2) type, linkage, comparison functions, etc. need not be specified at every - * call point. - */ - -#define rb_wrap(a_attr, a_prefix, a_tree_type, a_type, a_field, a_cmp) \ -a_attr void \ -a_prefix##new(a_tree_type *tree) { \ - rb_new(a_type, a_field, tree); \ -} \ -a_attr a_type * \ -a_prefix##first(a_tree_type *tree) { \ - a_type *ret; \ - rb_first(a_type, a_field, tree, ret); \ - return (ret); \ + /* Set root. */ \ + rbtree->rbt_root = path->node; \ + assert(rbtn_red_get(a_type, a_field, rbtree->rbt_root) == false); \ } \ a_attr a_type * \ -a_prefix##last(a_tree_type *tree) { \ - a_type *ret; \ - rb_last(a_type, a_field, tree, ret); \ - return (ret); \ +a_prefix##iter_recurse(a_rbt_type *rbtree, a_type *node, \ + a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg) { \ + if (node == &rbtree->rbt_nil) { \ + return (&rbtree->rbt_nil); \ + } else { \ + a_type *ret; \ + if ((ret = a_prefix##iter_recurse(rbtree, rbtn_left_get(a_type, \ + a_field, node), cb, arg)) != &rbtree->rbt_nil \ + || (ret = cb(rbtree, node, arg)) != NULL) { \ + return (ret); \ + } \ + return (a_prefix##iter_recurse(rbtree, rbtn_right_get(a_type, \ + a_field, node), cb, arg)); \ + } \ } \ a_attr a_type * \ -a_prefix##next(a_tree_type *tree, a_type *node) { \ - a_type *ret; \ - rb_next(a_type, a_field, a_cmp, tree, node, ret); \ - return (ret); \ +a_prefix##iter_start(a_rbt_type *rbtree, a_type *start, a_type *node, \ + a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg) { \ + int cmp = a_cmp(start, node); \ + if (cmp < 0) { \ + a_type *ret; \ + if ((ret = a_prefix##iter_start(rbtree, start, \ + rbtn_left_get(a_type, a_field, node), cb, arg)) != \ + &rbtree->rbt_nil || (ret = cb(rbtree, node, arg)) != NULL) { \ + return (ret); \ + } \ + return (a_prefix##iter_recurse(rbtree, rbtn_right_get(a_type, \ + a_field, node), cb, arg)); \ + } else if (cmp > 0) { \ + return (a_prefix##iter_start(rbtree, start, \ + rbtn_right_get(a_type, a_field, node), cb, arg)); \ + } else { \ + a_type *ret; \ + if ((ret = cb(rbtree, node, arg)) != NULL) { \ + return (ret); \ + } \ + return (a_prefix##iter_recurse(rbtree, rbtn_right_get(a_type, \ + a_field, node), cb, arg)); \ + } \ } \ a_attr a_type * \ -a_prefix##prev(a_tree_type *tree, a_type *node) { \ +a_prefix##iter(a_rbt_type *rbtree, a_type *start, a_type *(*cb)( \ + a_rbt_type *, a_type *, void *), void *arg) { \ a_type *ret; \ - rb_prev(a_type, a_field, a_cmp, tree, node, ret); \ + if (start != NULL) { \ + ret = a_prefix##iter_start(rbtree, start, rbtree->rbt_root, \ + cb, arg); \ + } else { \ + ret = a_prefix##iter_recurse(rbtree, rbtree->rbt_root, cb, arg);\ + } \ + if (ret == &rbtree->rbt_nil) { \ + ret = NULL; \ + } \ return (ret); \ } \ a_attr a_type * \ -a_prefix##search(a_tree_type *tree, a_type *key) { \ - a_type *ret; \ - rb_search(a_type, a_field, a_cmp, tree, key, ret); \ - return (ret); \ +a_prefix##reverse_iter_recurse(a_rbt_type *rbtree, a_type *node, \ + a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg) { \ + if (node == &rbtree->rbt_nil) { \ + return (&rbtree->rbt_nil); \ + } else { \ + a_type *ret; \ + if ((ret = a_prefix##reverse_iter_recurse(rbtree, \ + rbtn_right_get(a_type, a_field, node), cb, arg)) != \ + &rbtree->rbt_nil || (ret = cb(rbtree, node, arg)) != NULL) { \ + return (ret); \ + } \ + return (a_prefix##reverse_iter_recurse(rbtree, \ + rbtn_left_get(a_type, a_field, node), cb, arg)); \ + } \ } \ a_attr a_type * \ -a_prefix##nsearch(a_tree_type *tree, a_type *key) { \ - a_type *ret; \ - rb_nsearch(a_type, a_field, a_cmp, tree, key, ret); \ - return (ret); \ +a_prefix##reverse_iter_start(a_rbt_type *rbtree, a_type *start, \ + a_type *node, a_type *(*cb)(a_rbt_type *, a_type *, void *), \ + void *arg) { \ + int cmp = a_cmp(start, node); \ + if (cmp > 0) { \ + a_type *ret; \ + if ((ret = a_prefix##reverse_iter_start(rbtree, start, \ + rbtn_right_get(a_type, a_field, node), cb, arg)) != \ + &rbtree->rbt_nil || (ret = cb(rbtree, node, arg)) != NULL) { \ + return (ret); \ + } \ + return (a_prefix##reverse_iter_recurse(rbtree, \ + rbtn_left_get(a_type, a_field, node), cb, arg)); \ + } else if (cmp < 0) { \ + return (a_prefix##reverse_iter_start(rbtree, start, \ + rbtn_left_get(a_type, a_field, node), cb, arg)); \ + } else { \ + a_type *ret; \ + if ((ret = cb(rbtree, node, arg)) != NULL) { \ + return (ret); \ + } \ + return (a_prefix##reverse_iter_recurse(rbtree, \ + rbtn_left_get(a_type, a_field, node), cb, arg)); \ + } \ } \ a_attr a_type * \ -a_prefix##psearch(a_tree_type *tree, a_type *key) { \ +a_prefix##reverse_iter(a_rbt_type *rbtree, a_type *start, \ + a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg) { \ a_type *ret; \ - rb_psearch(a_type, a_field, a_cmp, tree, key, ret); \ - return (ret); \ -} \ -a_attr void \ -a_prefix##insert(a_tree_type *tree, a_type *node) { \ - rb_insert(a_type, a_field, a_cmp, tree, node); \ -} \ -a_attr void \ -a_prefix##remove(a_tree_type *tree, a_type *node) { \ - rb_remove(a_type, a_field, a_cmp, tree, node); \ -} - -/* - * The iterators simulate recursion via an array of pointers that store the - * current path. This is critical to performance, since a series of calls to - * rb_{next,prev}() would require time proportional to (n lg n), whereas this - * implementation only requires time proportional to (n). - * - * Since the iterators cache a path down the tree, any tree modification may - * cause the cached path to become invalid. In order to continue iteration, - * use something like the following sequence: - * - * { - * a_type *node, *tnode; - * - * rb_foreach_begin(a_type, a_field, a_tree, node) { - * ... - * rb_next(a_type, a_field, a_cmp, a_tree, node, tnode); - * rb_remove(a_type, a_field, a_cmp, a_tree, node); - * rb_foreach_next(a_type, a_field, a_cmp, a_tree, tnode); - * ... - * } rb_foreach_end(a_type, a_field, a_tree, node) - * } - * - * Note that this idiom is not advised if every iteration modifies the tree, - * since in that case there is no algorithmic complexity improvement over a - * series of rb_{next,prev}() calls, thus making the setup overhead wasted - * effort. - */ - -#define rb_foreach_begin(a_type, a_field, a_tree, a_var) { \ - /* Compute the maximum possible tree depth (3X the black height). */\ - unsigned rbp_f_height; \ - rbp_black_height(a_type, a_field, a_tree, rbp_f_height); \ - rbp_f_height *= 3; \ - { \ - /* Initialize the path to contain the left spine. */\ - a_type *rbp_f_path[rbp_f_height]; \ - a_type *rbp_f_node; \ - bool rbp_f_synced = false; \ - unsigned rbp_f_depth = 0; \ - if ((a_tree)->rbt_root != &(a_tree)->rbt_nil) { \ - rbp_f_path[rbp_f_depth] = (a_tree)->rbt_root; \ - rbp_f_depth++; \ - while ((rbp_f_node = rbp_left_get(a_type, a_field, \ - rbp_f_path[rbp_f_depth-1])) != &(a_tree)->rbt_nil) { \ - rbp_f_path[rbp_f_depth] = rbp_f_node; \ - rbp_f_depth++; \ - } \ - } \ - /* While the path is non-empty, iterate. */\ - while (rbp_f_depth > 0) { \ - (a_var) = rbp_f_path[rbp_f_depth-1]; - -/* Only use if modifying the tree during iteration. */ -#define rb_foreach_next(a_type, a_field, a_cmp, a_tree, a_node) \ - /* Re-initialize the path to contain the path to a_node. */\ - rbp_f_depth = 0; \ - if (a_node != NULL) { \ - if ((a_tree)->rbt_root != &(a_tree)->rbt_nil) { \ - rbp_f_path[rbp_f_depth] = (a_tree)->rbt_root; \ - rbp_f_depth++; \ - rbp_f_node = rbp_f_path[0]; \ - while (true) { \ - int rbp_f_cmp = (a_cmp)((a_node), \ - rbp_f_path[rbp_f_depth-1]); \ - if (rbp_f_cmp < 0) { \ - rbp_f_node = rbp_left_get(a_type, a_field, \ - rbp_f_path[rbp_f_depth-1]); \ - } else if (rbp_f_cmp > 0) { \ - rbp_f_node = rbp_right_get(a_type, a_field, \ - rbp_f_path[rbp_f_depth-1]); \ - } else { \ - break; \ - } \ - assert(rbp_f_node != &(a_tree)->rbt_nil); \ - rbp_f_path[rbp_f_depth] = rbp_f_node; \ - rbp_f_depth++; \ - } \ - } \ - } \ - rbp_f_synced = true; - -#define rb_foreach_end(a_type, a_field, a_tree, a_var) \ - if (rbp_f_synced) { \ - rbp_f_synced = false; \ - continue; \ - } \ - /* Find the successor. */\ - if ((rbp_f_node = rbp_right_get(a_type, a_field, \ - rbp_f_path[rbp_f_depth-1])) != &(a_tree)->rbt_nil) { \ - /* The successor is the left-most node in the right */\ - /* subtree. */\ - rbp_f_path[rbp_f_depth] = rbp_f_node; \ - rbp_f_depth++; \ - while ((rbp_f_node = rbp_left_get(a_type, a_field, \ - rbp_f_path[rbp_f_depth-1])) != &(a_tree)->rbt_nil) { \ - rbp_f_path[rbp_f_depth] = rbp_f_node; \ - rbp_f_depth++; \ - } \ - } else { \ - /* The successor is above the current node. Unwind */\ - /* until a left-leaning edge is removed from the */\ - /* path, or the path is empty. */\ - for (rbp_f_depth--; rbp_f_depth > 0; rbp_f_depth--) { \ - if (rbp_left_get(a_type, a_field, \ - rbp_f_path[rbp_f_depth-1]) \ - == rbp_f_path[rbp_f_depth]) { \ - break; \ - } \ - } \ - } \ - } \ + if (start != NULL) { \ + ret = a_prefix##reverse_iter_start(rbtree, start, \ + rbtree->rbt_root, cb, arg); \ + } else { \ + ret = a_prefix##reverse_iter_recurse(rbtree, rbtree->rbt_root, \ + cb, arg); \ } \ -} - -#define rb_foreach_reverse_begin(a_type, a_field, a_tree, a_var) { \ - /* Compute the maximum possible tree depth (3X the black height). */\ - unsigned rbp_fr_height; \ - rbp_black_height(a_type, a_field, a_tree, rbp_fr_height); \ - rbp_fr_height *= 3; \ - { \ - /* Initialize the path to contain the right spine. */\ - a_type *rbp_fr_path[rbp_fr_height]; \ - a_type *rbp_fr_node; \ - bool rbp_fr_synced = false; \ - unsigned rbp_fr_depth = 0; \ - if ((a_tree)->rbt_root != &(a_tree)->rbt_nil) { \ - rbp_fr_path[rbp_fr_depth] = (a_tree)->rbt_root; \ - rbp_fr_depth++; \ - while ((rbp_fr_node = rbp_right_get(a_type, a_field, \ - rbp_fr_path[rbp_fr_depth-1])) != &(a_tree)->rbt_nil) { \ - rbp_fr_path[rbp_fr_depth] = rbp_fr_node; \ - rbp_fr_depth++; \ - } \ - } \ - /* While the path is non-empty, iterate. */\ - while (rbp_fr_depth > 0) { \ - (a_var) = rbp_fr_path[rbp_fr_depth-1]; - -/* Only use if modifying the tree during iteration. */ -#define rb_foreach_reverse_prev(a_type, a_field, a_cmp, a_tree, a_node) \ - /* Re-initialize the path to contain the path to a_node. */\ - rbp_fr_depth = 0; \ - if (a_node != NULL) { \ - if ((a_tree)->rbt_root != &(a_tree)->rbt_nil) { \ - rbp_fr_path[rbp_fr_depth] = (a_tree)->rbt_root; \ - rbp_fr_depth++; \ - rbp_fr_node = rbp_fr_path[0]; \ - while (true) { \ - int rbp_fr_cmp = (a_cmp)((a_node), \ - rbp_fr_path[rbp_fr_depth-1]); \ - if (rbp_fr_cmp < 0) { \ - rbp_fr_node = rbp_left_get(a_type, a_field, \ - rbp_fr_path[rbp_fr_depth-1]); \ - } else if (rbp_fr_cmp > 0) { \ - rbp_fr_node = rbp_right_get(a_type, a_field,\ - rbp_fr_path[rbp_fr_depth-1]); \ - } else { \ - break; \ - } \ - assert(rbp_fr_node != &(a_tree)->rbt_nil); \ - rbp_fr_path[rbp_fr_depth] = rbp_fr_node; \ - rbp_fr_depth++; \ - } \ - } \ - } \ - rbp_fr_synced = true; - -#define rb_foreach_reverse_end(a_type, a_field, a_tree, a_var) \ - if (rbp_fr_synced) { \ - rbp_fr_synced = false; \ - continue; \ - } \ - if (rbp_fr_depth == 0) { \ - /* rb_foreach_reverse_sync() was called with a NULL */\ - /* a_node. */\ - break; \ - } \ - /* Find the predecessor. */\ - if ((rbp_fr_node = rbp_left_get(a_type, a_field, \ - rbp_fr_path[rbp_fr_depth-1])) != &(a_tree)->rbt_nil) { \ - /* The predecessor is the right-most node in the left */\ - /* subtree. */\ - rbp_fr_path[rbp_fr_depth] = rbp_fr_node; \ - rbp_fr_depth++; \ - while ((rbp_fr_node = rbp_right_get(a_type, a_field, \ - rbp_fr_path[rbp_fr_depth-1])) != &(a_tree)->rbt_nil) {\ - rbp_fr_path[rbp_fr_depth] = rbp_fr_node; \ - rbp_fr_depth++; \ - } \ - } else { \ - /* The predecessor is above the current node. Unwind */\ - /* until a right-leaning edge is removed from the */\ - /* path, or the path is empty. */\ - for (rbp_fr_depth--; rbp_fr_depth > 0; rbp_fr_depth--) {\ - if (rbp_right_get(a_type, a_field, \ - rbp_fr_path[rbp_fr_depth-1]) \ - == rbp_fr_path[rbp_fr_depth]) { \ - break; \ - } \ - } \ - } \ - } \ + if (ret == &rbtree->rbt_nil) { \ + ret = NULL; \ } \ + return (ret); \ } #endif /* RB_H_ */ -- cgit v1.1