timemodule.c revision 234f942aefb779efa6cfb7225e21d16a3f7e80f7
1/*********************************************************** 2Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum, 3Amsterdam, The Netherlands. 4 5 All Rights Reserved 6 7Permission to use, copy, modify, and distribute this software and its 8documentation for any purpose and without fee is hereby granted, 9provided that the above copyright notice appear in all copies and that 10both that copyright notice and this permission notice appear in 11supporting documentation, and that the names of Stichting Mathematisch 12Centrum or CWI not be used in advertising or publicity pertaining to 13distribution of the software without specific, written prior permission. 14 15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO 16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE 18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 23******************************************************************/ 24 25/* Time module */ 26 27#include "allobjects.h" 28#include "modsupport.h" 29#include "ceval.h" 30 31#include "sigtype.h" 32 33#include <signal.h> 34#include <setjmp.h> 35 36#ifdef BSD_TIME 37#define HAVE_GETTIMEOFDAY 38#include "myselect.h" /* Implies <sys/types.h>, <sys/time.h>, <sys/param.h> */ 39#endif 40 41#ifdef macintosh 42#define NO_UNISTD 43#endif 44 45#ifndef NO_UNISTD 46#include <unistd.h> 47#endif 48 49/* What happens here is not trivial. 50 The BSD_TIME code needs <sys/time.h> (for struct timeval). 51 The rest of the code needs only time_t, except some MS-DOS 52 code which needs clock_t as well. 53 Standard C says that time_t is defined in <time.h>, and 54 does not have <sys/types.h>; THINK C agrees (MS-DOS too?). 55 What's worse, in pure 4.3 BSD, older SunOS versions, and 56 probably everything derived from BSD, you can't #include 57 both <time.h> and <sys/time.h> in the same file, since 58 <sys/time.h> includes <time.h> without any protection, 59 and <time.h> contains a typedef, which can't be parsed twice! 60 So on traditional UNIX systems we include <sys/types.h> 61 and <sys/time.h> and hope this implies <time.h> and time_t, 62 while on other systems, including conforming Standard C 63 systems (where 'unix' can't be defined), we rely on <time.h>. 64 Still one problem: BSD_TIME won't work with strict Standard C... 65*/ 66 67#ifdef unix 68#include <sys/types.h> 69#include <sys/time.h> /* Implies <time.h> everywhere, as far as I know */ 70#else /* !unix */ 71#include <time.h> 72#endif /* !unix */ 73 74/* XXX This is bogus -- times() is defined in posixmodule.c */ 75#ifdef DO_TIMES 76#include <sys/times.h> 77#include <sys/param.h> 78#include <errno.h> 79#endif 80 81#ifdef SYSV 82/* Access timezone stuff */ 83#ifdef OLDTZ /* ANSI prepends underscore to these */ 84#define _timezone timezone /* seconds to be added to GMT */ 85#define _altzone 0 /* _timezone if daylight saving time */ 86#define _daylight 0 /* if zero, _altzone is not available*/ 87#define _tzname tzname /* Name of timezone and altzone */ 88#endif 89#ifdef NOALTTZ /* if system doesn't support alt tz */ 90#undef _daylight 91#undef _altzone 92#define _daylight 0 93#define _altzone 0 94#endif 95#endif /* SYSV */ 96 97/* Forward declarations */ 98static void floatsleep PROTO((double)); 99static long millitimer PROTO((void)); 100 101/* Time methods */ 102 103static object * 104time_time(self, args) 105 object *self; 106 object *args; 107{ 108#ifdef HAVE_GETTIMEOFDAY 109 struct timeval t; 110 struct timezone tz; 111 if (!getnoarg(args)) 112 return NULL; 113 if (gettimeofday(&t, &tz) != 0) { 114 err_errno(IOError); 115 return NULL; 116 } 117 return newfloatobject(t.tv_sec*1.0 + t.tv_usec*0.000001); 118#else /* !HAVE_GETTIMEOFDAY */ 119 time_t secs; 120 if (!getnoarg(args)) 121 return NULL; 122 time(&secs); 123#ifdef macintosh 124/* The Mac epoch is 1904, while UNIX uses 1970; Python prefers 1970 */ 125/* Moreover, the Mac returns local time. This we cannot fix... */ 126#define TIMEDIFF ((time_t) \ 127 (((1970-1904)*365L + (1970-1904)/4) * 24 * 3600)) 128 secs -= TIMEDIFF; 129#endif 130 return newfloatobject((double)secs); 131#endif /* !HAVE_GETTIMEOFDAY */ 132} 133 134static jmp_buf sleep_intr; 135 136/* ARGSUSED */ 137static void 138sleep_catcher(sig) 139 int sig; /* Not used but required by interface */ 140{ 141 longjmp(sleep_intr, 1); 142} 143 144static object * 145time_sleep(self, args) 146 object *self; 147 object *args; 148{ 149 double secs; 150 SIGTYPE (*sigsave)() = 0; /* Initialized to shut lint up */ 151 if (!getargs(args, "d", &secs)) 152 return NULL; 153 BGN_SAVE 154 if (setjmp(sleep_intr)) { 155 RET_SAVE 156 signal(SIGINT, sigsave); 157 err_set(KeyboardInterrupt); 158 return NULL; 159 } 160 sigsave = signal(SIGINT, SIG_IGN); 161 if (sigsave != (SIGTYPE (*)()) SIG_IGN) 162 signal(SIGINT, sleep_catcher); 163 floatsleep(secs); 164 END_SAVE 165 signal(SIGINT, sigsave); 166 INCREF(None); 167 return None; 168} 169 170#ifdef macintosh 171#define DO_MILLI 172#endif 173 174#ifdef AMOEBA 175#define DO_MILLI 176extern long sys_milli(); 177#define millitimer sys_milli 178#endif /* AMOEBA */ 179 180#ifdef BSD_TIME 181#define DO_MILLI 182#endif /* BSD_TIME */ 183 184#ifdef TURBO_C 185#define DO_MILLI 186#endif 187 188#ifdef DO_MILLI 189 190static object * 191time_millisleep(self, args) 192 object *self; 193 object *args; 194{ 195 long msecs; 196 SIGTYPE (*sigsave)(); 197 if (!getlongarg(args, &msecs)) 198 return NULL; 199 BGN_SAVE 200 if (setjmp(sleep_intr)) { 201 RET_SAVE 202 signal(SIGINT, sigsave); 203 err_set(KeyboardInterrupt); 204 return NULL; 205 } 206 sigsave = signal(SIGINT, SIG_IGN); 207 if (sigsave != (SIGTYPE (*)()) SIG_IGN) 208 signal(SIGINT, sleep_catcher); 209 floatsleep(msecs / 1000.0); 210 END_SAVE 211 signal(SIGINT, sigsave); 212 INCREF(None); 213 return None; 214} 215 216static object * 217time_millitimer(self, args) 218 object *self; 219 object *args; 220{ 221 long msecs; 222 if (!getnoarg(args)) 223 return NULL; 224 msecs = millitimer(); 225 return newintobject(msecs); 226} 227 228#endif /* DO_MILLI */ 229 230#ifdef DO_TIMES 231 232static object * 233time_times(self, args) 234 object *self; 235 object *args; 236{ 237 struct tms t; 238 clock_t c; 239 if (!getnoarg(args)) 240 return NULL; 241 errno = 0; 242 c = times(&t); 243 if (c == (clock_t) -1) { 244 err_errno(IOError); 245 return NULL; 246 } 247 return mkvalue("(dddd)", 248 (double)t.tms_utime / HZ, 249 (double)t.tms_stime / HZ, 250 (double)t.tms_cutime / HZ, 251 (double)t.tms_cstime / HZ); 252} 253 254#endif 255 256 257static object * 258time_convert(when, function) 259 time_t when; 260 struct tm * (*function) PROTO((time_t *)); 261{ 262 struct tm *p = function(&when); 263 return mkvalue("(iiiiiiiii)", 264 p->tm_year + 1900, 265 p->tm_mon + 1, /* Want January == 1 */ 266 p->tm_mday, 267 p->tm_hour, 268 p->tm_min, 269 p->tm_sec, 270 (p->tm_wday + 6) % 7, /* Want Monday == 0 */ 271 p->tm_yday, 272 p->tm_isdst); 273} 274 275static object * 276time_gmtime(self, args) 277 object *self; 278 object *args; 279{ 280 double when; 281 if (!getargs(args, "d", &when)) 282 return NULL; 283 return time_convert((time_t)when, gmtime); 284} 285 286static object * 287time_localtime(self, args) 288 object *self; 289 object *args; 290{ 291 double when; 292 if (!getargs(args, "d", &when)) 293 return NULL; 294 return time_convert((time_t)when, localtime); 295} 296 297/* Some very old systems may not have mktime(). Comment it out then! */ 298 299static object * 300time_mktime(self, args) 301 object *self; 302 object *args; 303{ 304 struct tm buf; 305 if (!getargs(args, "(iiiiiiiii)", 306 &buf.tm_year, 307 &buf.tm_mon, 308 &buf.tm_mday, 309 &buf.tm_hour, 310 &buf.tm_min, 311 &buf.tm_sec, 312 &buf.tm_wday, 313 &buf.tm_yday, 314 &buf.tm_isdst)) 315 return NULL; 316 if (buf.tm_year >= 1900) 317 buf.tm_year -= 1900; 318 buf.tm_mon--; 319 return newintobject((long)mktime(&buf)); 320} 321 322static struct methodlist time_methods[] = { 323#ifdef DO_MILLI 324 {"millisleep", time_millisleep}, 325 {"millitimer", time_millitimer}, 326#endif /* DO_MILLI */ 327#ifdef DO_TIMES 328 {"times", time_times}, 329#endif 330 {"sleep", time_sleep}, 331 {"time", time_time}, 332 {"gmtime", time_gmtime}, 333 {"localtime", time_localtime}, 334 {"mktime", time_mktime}, 335 {NULL, NULL} /* sentinel */ 336}; 337 338 339void 340inittime() 341{ 342 object *m, *d; 343 m = initmodule("time", time_methods); 344 d = getmoduledict(m); 345#ifdef SYSV 346 tzset(); 347 dictinsert(d, "timezone", newintobject((long)_timezone)); 348 dictinsert(d, "altzone", newintobject((long)_altzone)); 349 dictinsert(d, "daylight", newintobject((long)_daylight)); 350 dictinsert(d, "tzname", mkvalue("(zz)", _tzname[0], _tzname[1])); 351#else /* !SYSV */ 352 { 353#define YEAR ((time_t)((365 * 24 + 6) * 3600)) 354 time_t t; 355 struct tm *p; 356 long winterzone, summerzone; 357 char wintername[10], summername[10]; 358 t = (time((time_t *)0) / YEAR) * YEAR; 359 p = localtime(&t); 360 winterzone = -p->tm_gmtoff; 361 strncpy(wintername, p->tm_zone ? p->tm_zone : " ", 9); 362 wintername[9] = '\0'; 363 t += YEAR/2; 364 p = localtime(&t); 365 summerzone = -p->tm_gmtoff; 366 strncpy(summername, p->tm_zone ? p->tm_zone : " ", 9); 367 summername[9] = '\0'; 368 dictinsert(d, "timezone", newintobject(winterzone)); 369 dictinsert(d, "altzone", newintobject(summerzone)); 370 dictinsert(d, "daylight", 371 newintobject((long)(winterzone != summerzone))); 372 dictinsert(d, "tzname", 373 mkvalue("(zz)", wintername, summername)); 374 } 375#endif /* !SYSV */ 376} 377 378 379#ifdef macintosh 380 381#define MacTicks (* (long *)0x16A) 382 383#ifdef THINK_C_3_0 384sleep(secs) 385 int secs; 386{ 387 register long deadline; 388 389 deadline = MacTicks + mecs * 60; 390 while (MacTicks < deadline) { 391 if (intrcheck()) 392 sleep_catcher(SIGINT); 393 } 394} 395#endif 396 397static void 398floatsleep(secs) 399 double secs; 400{ 401 register long deadline; 402 403 deadline = MacTicks + (long)(secs * 60.0); 404 while (MacTicks < deadline) { 405 if (intrcheck()) 406 sleep_catcher(SIGINT); 407 } 408} 409 410static long 411millitimer() 412{ 413 return MacTicks * 50 / 3; /* MacTicks * 1000 / 60 */ 414} 415 416#endif /* macintosh */ 417 418 419#ifdef unix 420 421#ifdef BSD_TIME 422 423static long 424millitimer() 425{ 426 struct timeval t; 427 struct timezone tz; 428 if (gettimeofday(&t, &tz) != 0) 429 return -1; 430 return t.tv_sec*1000 + t.tv_usec/1000; 431} 432 433static void 434floatsleep(secs) 435 double secs; 436{ 437 struct timeval t; 438 double frac; 439 extern double fmod PROTO((double, double)); 440 extern double floor PROTO((double)); 441 frac = fmod(secs, 1.0); 442 secs = floor(secs); 443 t.tv_sec = (long)secs; 444 t.tv_usec = (long)(frac*1000000.0); 445 (void) select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t); 446} 447 448#else /* !BSD_TIME */ 449 450static void 451floatsleep(secs) 452 double secs; 453{ 454 sleep((int)secs); 455} 456 457#endif /* !BSD_TIME */ 458 459#endif /* unix */ 460 461 462#ifdef TURBO_C /* Maybe also for MS-DOS? */ 463 464#ifndef CLOCKS_PER_SEC 465#define CLOCKS_PER_SEC 55 /* 54.945 msec per tick (18.2 HZ clock) */ 466#endif 467 468static void 469floatsleep(secs) 470 double secs; 471{ 472 delay(long(secs/1000.0)); 473} 474 475static long 476millitimer() 477{ 478 clock_t ticks; 479 480 ticks = clock(); /* ticks since program start */ 481 return ticks * CLOCKS_PER_SEC;/* XXX shouldn't this be different? */ 482} 483 484#endif /* TURBO_C */ 485