diff options
Diffstat (limited to 'src/time')
| -rw-r--r-- | src/time/__tz.c | 1 | ||||
| -rw-r--r-- | src/time/__utc.c | 3 | ||||
| -rw-r--r-- | src/time/__year_to_secs.c | 4 | ||||
| -rw-r--r-- | src/time/clock_getcpuclockid.c | 1 | ||||
| -rw-r--r-- | src/time/clock_gettime.c | 3 | ||||
| -rw-r--r-- | src/time/strftime.c | 8 | ||||
| -rw-r--r-- | src/time/strptime.c | 66 | ||||
| -rw-r--r-- | src/time/timer_create.c | 37 | 
8 files changed, 111 insertions, 12 deletions
diff --git a/src/time/__tz.c b/src/time/__tz.c index c34b3eb7..54ed4cf6 100644 --- a/src/time/__tz.c +++ b/src/time/__tz.c @@ -24,7 +24,6 @@ weak_alias(__tzname, tzname);  static char std_name[TZNAME_MAX+1];  static char dst_name[TZNAME_MAX+1]; -const char __utc[] = "UTC";  static int dst_off;  static int r0[5], r1[5]; diff --git a/src/time/__utc.c b/src/time/__utc.c new file mode 100644 index 00000000..9e8bfc58 --- /dev/null +++ b/src/time/__utc.c @@ -0,0 +1,3 @@ +#include "time_impl.h" + +const char __utc[] = "UTC"; diff --git a/src/time/__year_to_secs.c b/src/time/__year_to_secs.c index 2824ec6d..b42f5a6d 100644 --- a/src/time/__year_to_secs.c +++ b/src/time/__year_to_secs.c @@ -10,9 +10,9 @@ long long __year_to_secs(long long year, int *is_leap)  		return 31536000*(y-70) + 86400*leaps;  	} -	int cycles, centuries, leaps, rem; +	int cycles, centuries, leaps, rem, dummy; -	if (!is_leap) is_leap = &(int){0}; +	if (!is_leap) is_leap = &dummy;  	cycles = (year-100) / 400;  	rem = (year-100) % 400;  	if (rem < 0) { diff --git a/src/time/clock_getcpuclockid.c b/src/time/clock_getcpuclockid.c index 8a0e2d4c..bce1e8ab 100644 --- a/src/time/clock_getcpuclockid.c +++ b/src/time/clock_getcpuclockid.c @@ -8,6 +8,7 @@ int clock_getcpuclockid(pid_t pid, clockid_t *clk)  	struct timespec ts;  	clockid_t id = (-pid-1)*8U + 2;  	int ret = __syscall(SYS_clock_getres, id, &ts); +	if (ret == -EINVAL) ret = -ESRCH;  	if (ret) return -ret;  	*clk = id;  	return 0; diff --git a/src/time/clock_gettime.c b/src/time/clock_gettime.c index c7e66a51..4d2ec22f 100644 --- a/src/time/clock_gettime.c +++ b/src/time/clock_gettime.c @@ -42,6 +42,9 @@ static int cgt_init(clockid_t clk, struct timespec *ts)  			p = cgt_time32_wrap;  		}  	} +#ifdef VDSO_CGT_WORKAROUND +	if (!__vdsosym(VDSO_CGT32_VER, VDSO_CGT32_SYM)) p = 0; +#endif  #endif  	int (*f)(clockid_t, struct timespec *) =  		(int (*)(clockid_t, struct timespec *))p; diff --git a/src/time/strftime.c b/src/time/strftime.c index cc53d536..c40246db 100644 --- a/src/time/strftime.c +++ b/src/time/strftime.c @@ -3,6 +3,7 @@  #include <string.h>  #include <langinfo.h>  #include <locale.h> +#include <ctype.h>  #include <time.h>  #include <limits.h>  #include "locale_impl.h" @@ -233,7 +234,12 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st  		pad = 0;  		if (*f == '-' || *f == '_' || *f == '0') pad = *f++;  		if ((plus = (*f == '+'))) f++; -		width = strtoul(f, &p, 10); +		if (isdigit(*f)) { +			width = strtoul(f, &p, 10); +		} else { +			width = 0; +			p = (void *)f; +		}  		if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') {  			if (!width && p!=f) width = 1;  		} else { diff --git a/src/time/strptime.c b/src/time/strptime.c index c54a0d8c..b1147242 100644 --- a/src/time/strptime.c +++ b/src/time/strptime.c @@ -59,6 +59,22 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri  			s = strptime(s, "%m/%d/%y", tm);  			if (!s) return 0;  			break; +		case 'F': +			/* Use temp buffer to implement the odd requirement +			 * that entire field be width-limited but the year +			 * subfield not itself be limited. */ +			i = 0; +			char tmp[20]; +			if (*s == '-' || *s == '+') tmp[i++] = *s++; +			while (*s=='0' && isdigit(s[1])) s++; +			for (; *s && i<(size_t)w && i+1<sizeof tmp; i++) { +				tmp[i] = *s++; +			} +			tmp[i] = 0; +			char *p = strptime(tmp, "%12Y-%m-%d", tm); +			if (!p) return 0; +			s -= tmp+i-p; +			break;  		case 'H':  			dest = &tm->tm_hour;  			min = 0; @@ -114,6 +130,13 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri  			s = strptime(s, "%H:%M", tm);  			if (!s) return 0;  			break; +		case 's': +			/* Parse only. Effect on tm is unspecified +			 * and presently no effect is implemented.. */ +			if (*s == '-') s++; +			if (!isdigit(*s)) return 0; +			while (isdigit(*s)) s++; +			break;  		case 'S':  			dest = &tm->tm_sec;  			min = 0; @@ -125,11 +148,30 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri  			break;  		case 'U':  		case 'W': -			/* Throw away result, for now. (FIXME?) */ +			/* Throw away result of %U, %V, %W, %g, and %G. Effect +			 * is unspecified and there is no clear right choice. */  			dest = &dummy;  			min = 0;  			range = 54;  			goto numeric_range; +		case 'V': +			dest = &dummy; +			min = 1; +			range = 53; +			goto numeric_range; +		case 'g': +			dest = &dummy; +			w = 2; +			goto numeric_digits; +		case 'G': +			dest = &dummy; +			if (w<0) w=4; +			goto numeric_digits; +		case 'u': +			dest = &tm->tm_wday; +			min = 1; +			range = 7; +			goto numeric_range;  		case 'w':  			dest = &tm->tm_wday;  			min = 0; @@ -154,6 +196,28 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri  			adj = 1900;  			want_century = 0;  			goto numeric_digits; +		case 'z': +			if (*s == '+') neg = 0; +			else if (*s == '-') neg = 1; +			else return 0; +			for (i=0; i<4; i++) if (!isdigit(s[1+i])) return 0; +			tm->__tm_gmtoff = (s[1]-'0')*36000+(s[2]-'0')*3600 +				+ (s[3]-'0')*600 + (s[4]-'0')*60; +			if (neg) tm->__tm_gmtoff = -tm->__tm_gmtoff; +			s += 5; +			break; +		case 'Z': +			if (!strncmp(s, tzname[0], len = strlen(tzname[0]))) { +				tm->tm_isdst = 0; +				s += len; +			} else if (!strncmp(s, tzname[1], len=strlen(tzname[1]))) { +				tm->tm_isdst = 1; +				s += len; +			} else { +				/* FIXME: is this supposed to be an error? */ +				while ((*s|32)-'a' <= 'z'-'a') s++; +			} +			break;  		case '%':  			if (*s++ != '%') return 0;  			break; diff --git a/src/time/timer_create.c b/src/time/timer_create.c index 4bef2390..cc6c2236 100644 --- a/src/time/timer_create.c +++ b/src/time/timer_create.c @@ -1,6 +1,7 @@  #include <time.h>  #include <setjmp.h>  #include <limits.h> +#include <semaphore.h>  #include "pthread_impl.h"  #include "atomic.h" @@ -12,7 +13,7 @@ struct ksigevent {  };  struct start_args { -	pthread_barrier_t b; +	sem_t sem1, sem2;  	struct sigevent *sev;  }; @@ -21,10 +22,16 @@ static void dummy_0()  }  weak_alias(dummy_0, __pthread_tsd_run_dtors); +static void timer_handler(int sig, siginfo_t *si, void *ctx) +{ +} +  static void cleanup_fromsig(void *p)  {  	pthread_t self = __pthread_self();  	__pthread_tsd_run_dtors(); +	__block_app_sigs(0); +	__syscall(SYS_rt_sigprocmask, SIG_BLOCK, SIGTIMER_SET, 0, _NSIG/8);  	self->cancel = 0;  	self->cancelbuf = 0;  	self->canceldisable = 0; @@ -42,7 +49,16 @@ static void *start(void *arg)  	void (*notify)(union sigval) = args->sev->sigev_notify_function;  	union sigval val = args->sev->sigev_value; -	pthread_barrier_wait(&args->b); +	/* The two-way semaphore synchronization ensures that we see +	 * self->cancel set by the parent if timer creation failed or +	 * self->timer_id if it succeeded, and informs the parent that +	 * we are done accessing the arguments so that the parent can +	 * proceed past their block lifetime. */ +	while (sem_wait(&args->sem1)); +	sem_post(&args->sem2); + +	if (self->cancel) +		return 0;  	for (;;) {  		siginfo_t si;  		while (sigwaitinfo(SIGTIMER_SET, &si) < 0); @@ -59,7 +75,7 @@ static void *start(void *arg)  int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict res)  { -	volatile static int init = 0; +	static volatile int init = 0;  	pthread_t td;  	pthread_attr_t attr;  	int r; @@ -88,7 +104,10 @@ int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict  		break;  	case SIGEV_THREAD:  		if (!init) { -			struct sigaction sa = { .sa_handler = SIG_DFL }; +			struct sigaction sa = { +				.sa_sigaction = timer_handler, +				.sa_flags = SA_SIGINFO | SA_RESTART +			};  			__libc_sigaction(SIGTIMER, &sa, 0);  			a_store(&init, 1);  		} @@ -97,7 +116,8 @@ int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict  		else  			pthread_attr_init(&attr);  		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); -		pthread_barrier_init(&args.b, 0, 2); +		sem_init(&args.sem1, 0, 0); +		sem_init(&args.sem2, 0, 0);  		args.sev = evp;  		__block_app_sigs(&set); @@ -113,10 +133,13 @@ int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict  		ksev.sigev_signo = SIGTIMER;  		ksev.sigev_notify = SIGEV_THREAD_ID;  		ksev.sigev_tid = td->tid; -		if (syscall(SYS_timer_create, clk, &ksev, &timerid) < 0) +		if (syscall(SYS_timer_create, clk, &ksev, &timerid) < 0) {  			timerid = -1; +			td->cancel = 1; +		}  		td->timer_id = timerid; -		pthread_barrier_wait(&args.b); +		sem_post(&args.sem1); +		while (sem_wait(&args.sem2));  		if (timerid < 0) return -1;  		*res = (void *)(INTPTR_MIN | (uintptr_t)td>>1);  		break;  | 
