1/* BEGIN LICENSE BLOCK 2 * Version: CMPL 1.1 3 * 4 * The contents of this file are subject to the Cisco-style Mozilla Public 5 * License Version 1.1 (the "License"); you may not use this file except 6 * in compliance with the License. You may obtain a copy of the License 7 * at www.eclipse-clp.org/license. 8 * 9 * Software distributed under the License is distributed on an "AS IS" 10 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 11 * the License for the specific language governing rights and limitations 12 * under the License. 13 * 14 * The Original Code is The ECLiPSe Constraint Logic Programming System. 15 * The Initial Developer of the Original Code is Cisco Systems, Inc. 16 * Portions created by the Initial Developer are 17 * Copyright (C) 1997-2006 Cisco Systems, Inc. All Rights Reserved. 18 * 19 * Contributor(s): 20 * 21 * END LICENSE BLOCK */ 22 23/*----------------------------------------------------------------------* 24 * ECLiPSe system 25 * 26 * IDENTIFICATION: os_support.c 27 * 28 * $Id: os_support.c,v 1.17 2015/05/05 15:11:30 jschimpf Exp $ 29 * 30 * AUTHOR: Joachim Schimpf, IC-Parc 31 * 32 * DESCRIPTION: Operating-system services abstraction layer 33 * 34 *----------------------------------------------------------------------*/ 35 36/*----------------------------------------------------------------------* 37 * Config & Prototypes only. 38 * Do not include any ECLiPSe-specific stuff in this file! 39 *----------------------------------------------------------------------*/ 40 41#include "config.h" 42#include "os_support.h" 43 44/*----------------------------------------------------------------------* 45 * OS-includes 46 *----------------------------------------------------------------------*/ 47 48#include <errno.h> 49#include <time.h> 50#include <sys/types.h> 51#include <sys/stat.h> /* for struct stat or _stat */ 52#include <stdio.h> 53#include <math.h> /* for floor() */ 54#include <ctype.h> /* for toupper() etc */ 55 56#ifdef _WIN32 57#if (HAVE_WIN32_WINNT >= 0x500) 58#define _WIN32_WINNT 0x500 /* for GetLongPathName() */ 59#else 60#define _WIN32_WINNT HAVE_WIN32_WINNT 61#endif 62/* FILETIMEs are in 100 nanosecond units */ 63#define FileTimeToDouble(t) ((double) (t).dwHighDateTime * 429.4967296 \ 64 + (double) (t).dwLowDateTime * 1e-7) 65#include <io.h> /* for _access(),... */ 66#include <process.h> /* for _getpid() */ 67#include <direct.h> /* for _getcwd() */ 68#include <sys/timeb.h> /* for _fstat() */ 69#include <conio.h> /* for _getch */ 70#include <windows.h> 71#else 72#include <sys/time.h> 73#include <sys/times.h> 74#include <pwd.h> 75#endif 76 77#ifdef STDC_HEADERS 78#include <stdlib.h> 79#else 80extern char *getenv(); 81#endif 82 83#ifdef HAVE_NETDB_H 84#include <netdb.h> /* for gethostbyname() */ 85#endif 86 87#ifdef HAVE_SYS_SYSTEMINFO_H 88#include <sys/systeminfo.h> /* for sysinfo() */ 89#endif 90 91#ifdef HAVE_STRING_H 92#include <string.h> 93#endif 94 95#ifdef HAVE_SYS_UTSNAME_H 96#include <sys/utsname.h> /* for uname() */ 97#endif 98 99#ifdef HAVE_TIMES 100#include <sys/times.h> 101#endif 102 103#ifdef BSD_TIMES 104#include <sys/timeb.h> 105#endif 106 107#ifdef HAVE_GETCWD 108#include <signal.h> 109#endif 110 111#ifdef HAVE_SIOCGIFHWADDR 112#include <sys/ioctl.h> 113#include <net/if.h> 114#endif 115 116#ifdef HAVE_PTHREAD_H 117#include <pthread.h> 118#endif 119 120/*----------------------------------------------------------------------* 121 * Global variables 122 *----------------------------------------------------------------------*/ 123 124/* 125 * ECLiPSe version number. This is here because it is needed for 126 * ec_env_lookup() and various executables. 127 */ 128char ec_version[] = PACKAGE_VERSION; 129 130/* 131 * the time when the system was started 132 */ 133#ifdef _WIN32 134static double start_time; /* in seconds */ 135#else 136#ifdef BSD_TIMES 137static time_t start_time; /* in seconds */ 138#else 139static clock_t start_time; /* in clock ticks */ 140#endif 141#endif 142 143/* 144 * the resolution of the system clock 145 */ 146int clock_hz; 147 148/* 149 * Error numbers of OS-errors 150 */ 151int ec_os_errno_; /* the operating system error number */ 152int ec_os_errgrp_; /* which group of error numbers it is from */ 153 154 155/* 156 * ECLiPSe's simulated working directory 157 * Used when ec_use_own_cwd != 0 158 */ 159 160int ec_use_own_cwd = 0; 161static char ec_cwd[MAX_PATH_LEN]; /* should always have a trailing '/' */ 162 163 164/*----------------------------------------------------------------------* 165 * Initialisation 166 *----------------------------------------------------------------------*/ 167 168void 169ec_os_init(void) 170{ 171 172#ifdef _WIN32 173 DWORD now; 174 FILETIME now_time; 175 GetSystemTimeAsFileTime(&now_time); 176 start_time = FileTimeToDouble(now_time); 177 now = now_time.dwLowDateTime; 178 clock_hz = CLOCKS_PER_SEC; 179 180#else /* UNIX */ 181 time_t now = time((time_t *) 0); 182 183#ifdef BSD_TIMES 184 start_time = now; /* init startup time */ 185#else 186 struct tms dummy; 187 start_time = times(&dummy); /* init startup time */ 188#endif 189#ifdef HAVE_SYSCONF 190 clock_hz = sysconf(_SC_CLK_TCK); 191#else 192#ifdef CLOCK_HZ 193 clock_hz = CLOCK_HZ; 194#else 195 clock_hz = 60; 196#endif 197#endif 198 199 /* On SUNOS 4.0 the first call to ctime() takes much longer than the 200 * subsequent ones since a shared file is opened (see tzsetup(8)). 201 * Therefore we call it here once. 202 */ 203 (void) ctime(&now); 204 205#endif 206 207#ifdef _WIN32 208 { 209 WSADATA wsa_data; 210 (void) WSAStartup(MAKEWORD(2,0), &wsa_data); /* init Winsock */ 211 } 212#endif 213 214 ec_use_own_cwd = 0; 215 (void) get_cwd(ec_cwd, MAX_PATH_LEN); 216} 217 218 219void 220ec_os_fini(void) 221{ 222#ifdef _WIN32 223 (void) WSACleanup(); /* finalise Winsock (once per WSAStartup()) */ 224#endif 225 ec_terminate_alarm(); /* terminate alarm thread, if any */ 226} 227 228 229/*----------------------------------------------------------------------* 230 * Simple wrappers for Windows -> Unix 231 *----------------------------------------------------------------------*/ 232 233#ifdef _WIN32 234 235#ifndef R_OK 236#define R_OK 4 237#define W_OK 2 238#define X_OK 1 239#endif 240 241int 242ec_access(char *name, int amode) 243{ 244 /* CAUTION: Windows _access() knows only R_OK and W_OK. 245 * http://msdn.microsoft.com/en-us/library/1w06ktdy.aspx 246 * To simulate X_OK check we use _stat() and check for _S_IEXEC mode, 247 * but even that is fake: it is set when the file name has a .exe 248 * extension, and is always set for directories. 249 * A cleaner implementation would probably use AccessCheck(), 250 * OpenThreadToken(), etc. 251 */ 252 char winname[MAX_PATH_LEN]; 253 254 os_filename(name, winname); 255 if (_access(winname, amode & (R_OK|W_OK))) 256 return -1; 257 if (amode & X_OK) 258 { 259 struct _stat buf; 260 if (_stat(winname, &buf)) 261 return -1; 262 if (!(buf.st_mode & _S_IEXEC)) 263 return -1; 264 } 265 return 0; 266} 267 268int 269getpid(void) 270{ 271 return _getpid(); 272} 273 274int 275ec_chdir(char *name) 276{ 277 char winname[MAX_PATH_LEN]; 278 return _chdir(os_filename(name, winname)); 279} 280 281int 282ec_stat(char *name, struct_stat *buf) 283{ 284 char winname[MAX_PATH_LEN]; 285 return _stat(os_filename(name, winname), (struct _stat *) buf); 286} 287 288#ifndef __GNUC__ 289int 290fstat(int handle, struct_stat *buf) 291{ 292 return _fstat(handle, buf); 293} 294#endif 295 296int 297ec_rmdir(char *name) 298{ 299 char winname[MAX_PATH_LEN]; 300 return _rmdir(os_filename(name, winname)); 301} 302 303int 304ec_mkdir(char *name, int mode) 305{ 306 char winname[MAX_PATH_LEN]; 307 return _mkdir(os_filename(name, winname)); 308} 309 310int 311ec_unlink(char *name) 312{ 313 char winname[MAX_PATH_LEN]; 314 return _unlink(os_filename(name, winname)); 315} 316 317#ifndef __GNUC__ 318long 319lseek(int handle, long offset, int whence) 320{ 321 return _lseek(handle, offset, whence); 322} 323#endif 324 325int 326ec_truncate(int fd) 327{ 328 if (!SetEndOfFile((HANDLE)_get_osfhandle(fd))) 329 { 330 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 331 return -1; 332 } 333 return 0; 334} 335 336#ifndef __GNUC__ 337int 338putenv(char *envstring) 339{ 340 return _putenv(envstring); 341} 342#endif 343 344int 345isatty(int handle) 346{ 347 return _isatty(handle); 348} 349 350#ifndef isascii 351/* isascii is defined as a macro (as __isascii) in newer versions of MSVC, 352 and also in more recent versions of MinGW 353*/ 354int 355isascii(int c) 356{ 357 return __isascii(c); 358} 359#endif 360 361int 362ec_open(const char *name, int oflag, int pmode) 363{ 364 char winname[MAX_PATH_LEN]; 365 return _open(os_filename((char *) name, winname), oflag|_O_BINARY, pmode); 366} 367 368int 369dup(int handle) 370{ 371 return _dup(handle); 372} 373 374int 375dup2(int h1, int h2) 376{ 377 return _dup2(h1, h2); 378} 379 380int 381close(int handle) 382{ 383 return _close(handle); 384} 385 386int 387read(int handle, void *buf, unsigned int count) 388{ 389 return _read(handle, buf, count); 390} 391 392int 393write(int handle, const void *buf, unsigned int count) 394{ 395 return _write(handle, buf, count); 396} 397 398int 399pipe(int *fd) 400{ 401 /* _O_NOINHERIT is important for pipes used in exec */ 402 return _pipe(fd, 4096, _O_BINARY|_O_NOINHERIT); 403} 404 405int 406getpagesize(void) 407{ 408 SYSTEM_INFO info; 409 GetSystemInfo(&info); 410 return (int) info.dwPageSize; 411} 412#endif 413 414int 415ec_rename(char *old, char *new) 416{ 417 char winold[MAX_PATH_LEN]; 418 char winnew[MAX_PATH_LEN]; 419 return rename(os_filename(old, winold), os_filename(new, winnew)); 420} 421 422 423 424/*----------------------------------------------------------------------* 425 * Filename conversions 426 *----------------------------------------------------------------------*/ 427 428/* 429 * Automaton for syntactic cleanup of (absolute or relative) pathnames: 430 * Remove redundant slashes, . and .. 431 * Produce: //share/dir/file //c/dir/file /dir/file dir/file file 432 * The result will never be longer than the input, and in=out is allowed. 433 */ 434 435static char * 436_cleanup_path(char *inp, char *out, char *out_last) 437{ 438 int c; 439 char *outp = out; 440 char *top = out; /* highest point in the path */ 441 int absolute = 0; /* it's an absolute path (we can't go beyond top) */ 442 443#define Emit(c) { if (outp<out_last) *outp++ = (c); else goto _terminate_; } 444 445 switch (c = *inp++) { 446 case '.': goto _initial_dot_; 447 case '/': Emit(c); goto _abs_; 448 case 0: goto _terminate_; 449 default: goto _name_; 450 } 451_initial_dot_: 452 switch (c = *inp++) { 453 case '.': goto _initial_up_; 454 case '/': goto _rel_; 455 case 0: Emit('.'); goto _terminate_; 456 default: Emit('.'); goto _name_; 457 } 458_initial_up_: 459 switch (c = *inp++) { 460 case '/': Emit('.'); Emit('.'); Emit('/'); top=outp; goto _sep_; 461 case 0: Emit('.'); Emit('.'); goto _terminate_; 462 case '.': 463 default: Emit('.'); Emit('.'); goto _name_; 464 } 465_rel_: 466 switch (c = *inp++) { 467 case '.': goto _initial_dot_; 468 case '/': goto _rel_; 469 case 0: Emit('.'); goto _terminate_; 470 default: top=outp; goto _name_; 471 } 472_abs_: 473 absolute = 1; 474 switch (c = *inp++) { 475 case '.': top=outp; goto _dot_; 476 case '/': goto _unc_; 477 case 0: goto _terminate_; 478 default: top=outp; goto _name_; 479 } 480_unc_: 481 switch (c = *inp++) { 482 case '.': top=outp; goto _dot_; /* treat //. like /. */ 483 case '/': goto _unc_; /* treat /// like // */ 484 case 0: goto _terminate_; /* treat // like / */ 485 default: Emit('/'); goto _share_; /* treat ///a like //a */ 486 } 487_share_: 488 Emit(c); 489 switch (c = *inp++) { 490 case '/': Emit(c); top=outp; goto _sep_; 491 case 0: goto _terminate_; 492 default: goto _share_; 493 } 494_sep_: 495 switch (c = *inp++) { 496 case '/': goto _sep_; 497 case '.': goto _dot_; 498 case 0: goto _done_; 499 default: goto _name_; 500 } 501_dot_: 502 switch (c = *inp++) { 503 case 0: goto _done_; /* ignore trailing . */ 504 case '.': goto _up_; 505 case '/': goto _sep_; /* ignore /./ */ 506 default: Emit('.'); goto _name_; 507 } 508_up_: 509 switch(c = *inp++) { 510 case 0: 511 case '/': 512 if (outp>top) { 513 /* back to after previous / or top */ 514 while(--outp > top && *(outp-1) != '/') 515 continue; 516 } else if (!absolute) { 517 Emit('.'); Emit('.'); Emit('/'); top=outp; 518 } 519 if (c) goto _sep_; else goto _done_; 520 default: 521 Emit('.'); Emit('.'); goto _name_; 522 } 523_name_: 524 Emit(c); 525 switch (c = *inp++) { 526 case '/': Emit(c); goto _sep_; 527 case 0: goto _terminate_; 528 default: goto _name_; 529 } 530_done_: 531 if (outp == out) { 532 Emit('.') /* no other path component */ 533 } else if (outp > out+1 && *(outp-1) == '/') { 534 --outp; /* omit trailing slash */ 535 } 536_terminate_: 537 *outp = 0; 538 return out; 539} 540 541 542/* 543 * char *expand_filename(in, out, option) 544 * 545 * EXPAND_SYNTACTIC 546 * expand ~, ~user and $VAR at the beginning of the filename 547 * EXPAND_STANDARD 548 * also make absolute (only if necessary) 549 * EXPAND_ABSOLUTE 550 * also make absolute (always) 551 * EXPAND_NORMALISE 552 * full normalisation (symlinks, Windows capitalisation etc) 553 * In addition, unneeded sequences /, ./ are removed. 554 * 555 * out should point to a buffer of length MAX_PATH_LEN. 556 * The return value is a pointer to the expanded filename in out[]. 557 * It can be used like 558 * 559 * char buf[MAX_PATH_LEN]; 560 * name = expand_filename(name, buf, EXPAND_STANDARD); 561 * 562 * No errors are returned. When there was a problem, we just 563 * return a copy of the original string. 564 * The result is truncated to MAX_PATH_LEN, without warning! 565 */ 566 567#define Str_Cpy(to, from, to_last) \ 568 { while(*(from) && (to)<(to_last)) *(to)++ = *(from)++; } 569#define Str_Cpy_Until(to, from, delim, to_last) \ 570 { while(*(from) && *(from) != (delim) && (to) < (to_last)) *(to)++ = *(from)++; } 571 572char * 573expand_filename(char *in, char *out, int option) 574{ 575 int c; 576 char *inp = in; 577 char *dir = (char *) 0; 578 char aux1[MAX_PATH_LEN], *aux1p = 0; 579 char * const aux1_last = &aux1[MAX_PATH_LEN-1]; 580 char aux[MAX_PATH_LEN], *auxp = 0; 581 char * const aux_last = &aux[MAX_PATH_LEN-1]; 582 char * const out_last = out+MAX_PATH_LEN-1; 583 584 /* When not using the process's cwd, we MUST use absolute paths */ 585 if (option == EXPAND_STANDARD && ec_use_own_cwd) 586 option = EXPAND_ABSOLUTE; 587 588 /* 589 * Expand tilde and environment variables 590 * inp=in=<input path> 591 */ 592 switch(*inp) 593 { 594 case '~': 595 if (*++inp == '/' || *inp == '\0') 596 { 597 char *home, *drv; 598 auxp = aux; 599 aux1p = aux1; 600#ifdef _WIN32 601 if ((drv = getenv("HOMEDRIVE")) && (home = getenv("HOMEPATH"))) 602 { 603 auxp = aux; 604 Str_Cpy(auxp, drv, aux_last); 605 Str_Cpy(auxp, home, aux_last); 606 *auxp = 0; 607 aux1p = canonical_filename(aux, aux1); 608 } 609 else 610#endif 611 if ((home = getenv("HOME")) && strlen(home) < MAX_PATH_LEN) 612 { 613 aux1p = canonical_filename(home, aux1); 614 } 615 else 616 { 617 aux1p = 0; 618 } 619 } 620#ifndef _WIN32 621 else 622 { 623 struct passwd *pass; 624 auxp = aux; 625 Str_Cpy_Until(auxp, inp, '/', aux_last); 626 *auxp = '\0'; 627 if ((pass = getpwnam(aux)) && strlen(pass->pw_dir) < MAX_PATH_LEN) 628 aux1p = canonical_filename(pass->pw_dir, aux1); 629 } 630#endif 631 break; 632 case '$': 633 { 634 int size = MAX_PATH_LEN; 635 ++inp; 636 aux1p = aux1; 637 Str_Cpy_Until(aux1p, inp, '/', aux1_last); 638 *aux1p = '\0'; 639 if (ec_env_lookup(aux1, aux, &size) && size <= MAX_PATH_LEN) 640 aux1p = canonical_filename(aux, aux1); /* make sure it is in ECLiPSe format */ 641 else aux1p = 0; 642 } 643 break; 644 } 645 646 if (aux1p) 647 { 648 /* append rest of input to expanded prefix in aux1[] */ 649 aux1p += strlen(aux1p); 650 Str_Cpy(aux1p, inp, aux1_last); 651 *aux1p = 0; 652 inp = aux1; 653 } 654 else /* no prefix was expanded */ 655 { 656 inp = in; 657 } 658 659 660 /* 661 * Make absolute, i.e. add cwd or drive 662 * inp points to result so far, either in in[] or aux1[] 663 */ 664 if (option >= EXPAND_ABSOLUTE) 665 { 666 if (inp[0] != '/') /* relative path: prefix cwd */ 667 { 668 auxp = aux + ec_get_cwd(aux, MAX_PATH_LEN); 669 Str_Cpy(auxp, inp, aux_last); 670 *auxp = 0; 671 inp = aux; 672 } 673#ifdef _WIN32 674 else if (inp[1] != '/') /* drive relative: prefix drive */ 675 { 676 auxp = aux; 677 ec_get_cwd(aux, MAX_PATH_LEN); 678 while (*auxp == '/') ++auxp; /* copy share/drive name */ 679 while (*auxp != '/') ++auxp; 680 Str_Cpy(auxp, inp, aux_last); 681 *auxp = 0; 682 inp = aux; 683 } 684#endif 685 } 686 687 688 /* 689 * Full normalise: symlinks etc 690 * inp points to result so far, either in in[], aux1[] or aux[] 691 */ 692 if (option == EXPAND_NORMALISE) 693 { 694#if defined(_WIN32) && (_WIN32_WINNT > 0x400) 695 int len; 696 char buf1[MAX_PATH_LEN]; 697 char buf2[MAX_PATH_LEN]; 698 /* Get `normalised' path with correct cases for characters in path. 699 GetLongPathName() is supported only by Windows NT > 4 700 XP seems to require a call to GetShortPathName(), otherwise 701 GetLongPathName() does not always behave correctly. 702 */ 703 os_filename(inp, buf2); 704 /* Make sure drive letter is upper case (bug under cygwin) */ 705 if (islower(buf2[0]) && buf2[1] == ':') 706 buf2[0] = toupper(buf2[0]); 707 len = GetShortPathName(buf2, buf1, MAX_PATH_LEN); 708 if (0 < len && len < MAX_PATH_LEN) 709 { 710 len = GetLongPathName(buf1, buf2, MAX_PATH_LEN); 711 if (0 < len && len < MAX_PATH_LEN) { 712 canonical_filename(buf2, buf1); 713 _cleanup_path(buf1, out, out_last); 714 } else { 715 canonical_filename(buf1, buf2); 716 _cleanup_path(buf2, out, out_last); 717 } 718 } 719 else 720 { 721 canonical_filename(buf2, buf1); 722 _cleanup_path(buf1, out, out_last); 723 } 724 725#elif HAVE_REALPATH 726 /* realpath() also cleans up /. and /.. */ 727 if (!realpath(inp, out)) 728 { 729 errno = 0; 730 _cleanup_path(inp, out, out_last); 731 } 732 733#else 734 _cleanup_path(inp, out, out_last); 735#endif 736 } 737 else 738 { 739 _cleanup_path(inp, out, out_last); 740 } 741 742 return out; 743} 744 745 746char * 747canonical_filename(char *in, char *out) 748{ 749#ifdef _WIN32 750 char *s = in; 751 char *t = out; 752 for (;;) 753 { 754 if (*s == '\0' || *s == '\\' || *s == '/') 755 { 756 s = in; /* no drive letter */ 757 break; 758 } 759 if (*s == ':') /* copy drive name */ 760 { 761 *t++ = '/'; 762 *t++ = '/'; 763 while (in < s) 764 *t++ = *in++; 765 ++s; 766 if (*s != '\\' && *s != '/') 767 *t++ = '/'; /* no separator, insert one */ 768 break; 769 } 770 ++s; 771 } 772 while (*s) /* copy, replacing \ with / */ 773 { 774 *t = (*s == '\\') ? '/' : *s; 775 ++s; ++t; 776 } 777 778 *t = '\0'; 779 return out; 780#else 781 return strcpy(out, in); 782#endif 783} 784 785char * 786os_filename(char *in, char *out) 787{ 788#ifdef _WIN32 789 char *eos; 790 char *t = out; 791 792 /* interpret //? as a drive name and treat specially */ 793 if (in[0] == '/' && in[1] == '/' && in[2] != 0 && (in[3] == '/' || in[3] == 0)) 794 { 795 *t++ = in[2]; /* copy drive letter */ 796 *t++ = ':'; /* followed by : */ 797 *t++ = '\\'; 798 if (in[3]==0 || in[4]==0) 799 { 800 /* special case //D[/] -> D:\. rather than simply D: (bug 465) */ 801 *t++ = '.'; *t = '\0'; 802 return out; 803 } 804 in += 4; 805 } 806 else if (*in == '/') /* one or two non-trimmable slashes */ 807 { 808 *t++ = '\\'; ++in; 809 if (*in == '/') 810 { 811 *t++ = '\\'; ++in; 812 } 813 } 814 eos = t; 815 while (*in) /* copy rest of path */ 816 { 817 if (*in == '/') 818 { 819 *t++ = '\\'; 820 ++in; 821 } 822 else 823 { 824 *t++ = *in++; 825 eos = t; /* to remove trailing slashes */ 826 } 827 } 828 *eos = '\0'; 829 return out; 830#else 831 return strcpy(out, in); 832#endif 833} 834 835 836/*----------------------------------------------------------------------* 837 * Directories 838 *----------------------------------------------------------------------*/ 839 840/* 841* For the sps7 there is a special getwd() code. It works on other 842* machines as well, however it is not necessary to duplicate everything. 843*/ 844#if !defined(_WIN32) && !defined(HAVE_GETCWD) && !defined(HAVE_GETWD) 845#include "getwd.c" 846#endif 847 848/* 849* Get the current working directory (unix) into a buffer 850* and add a trailing "/". If something went wrong, return "./". 851* The return code is the string length. 852* Different code is needed for different operating systems. 853*/ 854 855/*ARGSUSED*/ 856int 857get_cwd(char *buf, int size) 858{ 859 char *s; 860 int len; 861 char buf1[MAX_PATH_LEN]; 862 863#ifdef _WIN32 864 char buf2[MAX_PATH_LEN]; 865 s = _getcwd(buf1, MAX_PATH_LEN); 866 /* Make sure drive letter is upper case (bug under cygwin) */ 867 if (islower(buf1[0]) && buf1[1] == ':') 868 buf1[0] = toupper(buf1[0]); 869#if _WIN32_WINNT > 0x400 870 /* Get `normalised' path with correct cases for characters in path. 871 GetLongPathName() is supported only by Windows NT > 4 872 XP seems to require a call to GetShortPathName(), otherwise 873 GetLongPathName() does not always behave correctly. 874 */ 875 len = GetShortPathName(buf1, buf2, MAX_PATH_LEN); 876 if (len > 0) 877 { 878 len = GetLongPathName(buf2, buf1, MAX_PATH_LEN); 879 if (len == 0) s = _getcwd(buf1, MAX_PATH_LEN); 880 } 881#endif 882#else 883#ifdef HAVE_GETCWD 884 /* Signal blocking here is to work around a bug that occurred 885 * on Suns when the profiler signal interupts getcwd() 886 */ 887# ifdef HAVE_SIGPROCMASK 888 sigset_t old_mask, block_mask; 889 (void) sigemptyset(&block_mask); 890 (void) sigaddset(&block_mask, SIGPROF); 891 (void) sigprocmask(SIG_BLOCK, &block_mask, &old_mask); 892# else 893# ifdef HAVE_SIGVEC 894 int old_mask = sigblock(sigmask(SIGPROF)); 895# endif 896# endif 897 s = getcwd(buf1, (size_t) MAX_PATH_LEN); 898# ifdef HAVE_SIGPROCMASK 899 (void) sigprocmask(SIG_SETMASK, &old_mask, (sigset_t *) 0); 900# else 901# ifdef HAVE_SIGVEC 902 (void) sigsetmask(old_mask); 903# endif 904# endif 905#else 906 s = getwd(buf1); /* system or our own definition from getwd.c */ 907#endif 908#endif 909 if (s == 0) { /* return local path if something went wrong */ 910 errno = 0; 911 buf[0] = '.'; 912 buf[1] = '/'; 913 buf[2] = '\0'; 914 return 2; 915 } 916 len = strlen(canonical_filename(buf1, buf)); 917 if (buf[len-1] != '/') /* add trailing / if needed */ 918 { 919 buf[len++] = '/'; 920 buf[len] = '\0'; 921 } 922 return len; 923} 924 925 926/* return string length (without terminator) */ 927int 928ec_get_cwd(char *buf, int size) 929{ 930 if (ec_use_own_cwd) 931 { 932 strcpy(buf, ec_cwd); 933 return strlen(ec_cwd); 934 } 935 else 936 { 937 return get_cwd(buf, size); 938 } 939} 940 941/* return 0 on success, -1 on error with Sys_Errno */ 942int 943ec_set_cwd(char *name) 944{ 945 if (ec_use_own_cwd) 946 { 947 char buf[MAX_PATH_LEN]; 948 int len; 949 struct_stat st_buf; 950 name = expand_filename(name, buf, EXPAND_NORMALISE); 951 if (ec_stat(name, &st_buf)) { 952 Set_Sys_Errno(errno, ERRNO_UNIX); 953 return -1; 954 } 955 if (!S_ISDIR(st_buf.st_mode)) { 956 Set_Sys_Errno(ENOTDIR, ERRNO_UNIX); /* simulate chdir() */ 957 return -1; 958 } 959 strcpy(ec_cwd, buf); 960 len = strlen(ec_cwd); 961 if (ec_cwd[len-1] != '/') { 962 ec_cwd[len] = '/'; 963 ec_cwd[len+1] = 0; 964 } 965 966 } else if (ec_chdir(name)) { 967 Set_Sys_Errno(errno, ERRNO_UNIX); 968 return -1; 969 } 970 return 0; 971} 972 973 974/*----------------------------------------------------------------------* 975 * dlopen 976 *----------------------------------------------------------------------*/ 977 978/* use the dlopen compatibility code for MacOSX */ 979#if !defined(HAVE_DLOPEN) && defined(HAVE_MACH_O_DYLD_H) 980#include "dlfcn_simple.c" 981#endif 982 983/*----------------------------------------------------------------------* 984 * Times 985 *----------------------------------------------------------------------*/ 986 987/* 988 * User CPU time in clock ticks. 989 * The elapsed time in seconds can be computed as 990 * user_time() / clock_hz 991 */ 992long 993user_time(void) 994{ 995#ifdef _WIN32 996 FILETIME creation_time, exit_time, kernel_time, user_time; 997 LARGE_INTEGER li; 998 999 if (GetProcessTimes(GetCurrentProcess(), 1000 &creation_time, &exit_time, &kernel_time, &user_time)) 1001 { 1002 li.LowPart = user_time.dwLowDateTime; 1003 li.HighPart = user_time.dwHighDateTime; 1004 return (long) (li.QuadPart / (10000000/CLOCKS_PER_SEC)); 1005 } 1006 else 1007 { 1008 return (long) clock(); 1009 } 1010#else 1011#if defined(HAVE_TIMES) 1012 struct tms rusag; 1013 1014 (void) times(&rusag); 1015 return rusag.tms_utime; 1016#else 1017 /* try at least with the real time */ 1018 return (long) time((time_t *) 0); 1019#endif 1020#endif 1021} 1022 1023 1024/* 1025 * Time in seconds since birth of UNIX 1026 */ 1027long 1028ec_unix_time(void) 1029{ 1030 return (long) time((time_t *) 0); 1031} 1032 1033 1034/* 1035 * User-CPU, System-CPU and Elapsed time for this Eclipse process as floats 1036 */ 1037int 1038all_times(double *user, double *sys, double *elapsed) /* in seconds */ 1039{ 1040 1041#ifdef _WIN32 1042 1043 FILETIME creation_time, exit_time, kernel_time, user_time, now_time; 1044 1045 if (GetProcessTimes(GetCurrentProcess(), 1046 &creation_time, &exit_time, &kernel_time, &user_time)) 1047 { 1048 *user = FileTimeToDouble(user_time); 1049 *sys = FileTimeToDouble(kernel_time); 1050 } 1051 else 1052 { 1053 *user = ((double) clock() / CLOCKS_PER_SEC); 1054 *sys = 0; 1055 } 1056 GetSystemTimeAsFileTime(&now_time); 1057 *elapsed = FileTimeToDouble(now_time) - start_time; 1058 1059#else /* UNIX */ 1060 1061 struct tms rusag; 1062#ifdef BSD_TIMES 1063 struct timeb realtime; 1064 /* times() returns nothing useful in BSD, need ftime() for elapsed time */ 1065 (void) ftime(&realtime); 1066 if (times(&rusag) == -1) 1067 { 1068 return(-1); 1069 } 1070 *elapsed = (realtime.time - start_time) + (double)realtime.millitm/1000.0; 1071#else 1072 clock_t realtime; 1073 if ((realtime = times(&rusag)) == (clock_t) -1) 1074 { 1075 return(-1); 1076 } 1077 *elapsed = (double) (realtime - start_time) / clock_hz; 1078#endif 1079 1080 *user = (double) rusag.tms_utime / clock_hz; 1081 *sys = (double) rusag.tms_stime / clock_hz; 1082 1083#endif 1084 return 0; 1085} 1086 1087 1088char * 1089ec_date_string(char *buf) 1090{ 1091 time_t ti = (long) time((time_t *) 0); 1092 strcpy(buf, ctime(&ti)); 1093 return buf; 1094} 1095 1096 1097/*----------------------------------------------------------------------* 1098 * Other system services 1099 *----------------------------------------------------------------------*/ 1100 1101 1102int 1103ec_gethostid(char *buf, int len) 1104{ 1105 1106#ifdef _WIN32 1107 1108 /* 1109 * This code taken from 1110 * http://support.microsoft.com/kb/q118623/ 1111 * It gets (an) Ethernet adapter hardware address, same as 1112 * ioctl(..., SIOCGIFHWADDR, ...) in Linux. 1113 */ 1114 1115 typedef struct _ASTAT_ 1116 { 1117 ADAPTER_STATUS adapt; 1118 NAME_BUFFER NameBuff [30]; 1119 } ASTAT; 1120 1121 NCB Ncb; 1122 ASTAT Adapter; 1123 LANA_ENUM lenum; 1124 int i; 1125 1126 memset( &Ncb, 0, sizeof(Ncb) ); 1127 Ncb.ncb_command = NCBENUM; 1128 Ncb.ncb_buffer = (UCHAR *)&lenum; 1129 Ncb.ncb_length = sizeof(lenum); 1130 if (Netbios( &Ncb ) != 0) 1131 return -1; 1132 1133 for(i=0; i < lenum.length ;i++) 1134 { 1135 memset( &Ncb, 0, sizeof(Ncb) ); 1136 Ncb.ncb_command = NCBRESET; 1137 Ncb.ncb_lana_num = lenum.lana[i]; 1138 if (Netbios( &Ncb ) != 0) 1139 return -1; 1140 1141 memset( &Ncb, 0, sizeof (Ncb) ); 1142 Ncb.ncb_command = NCBASTAT; 1143 Ncb.ncb_lana_num = lenum.lana[i]; 1144 strcpy( Ncb.ncb_callname, "* " ); 1145 Ncb.ncb_buffer = (char *) &Adapter; 1146 Ncb.ncb_length = sizeof(Adapter); 1147 if (Netbios( &Ncb ) != 0) 1148 return -1; 1149 1150 sprintf(buf, "A#%02x%02x%02x%02x%02x%02x", 1151 Adapter.adapt.adapter_address[0], 1152 Adapter.adapt.adapter_address[1], 1153 Adapter.adapt.adapter_address[2], 1154 Adapter.adapt.adapter_address[3], 1155 Adapter.adapt.adapter_address[4], 1156 Adapter.adapt.adapter_address[5]); 1157 1158 /* return the first one we can get hold of */ 1159 break; 1160 } 1161 1162#else 1163 1164#if defined(HAVE_SYSINFO) && defined(HAVE_SYS_SYSTEMINFO_H) 1165 1166 char *bufp = buf; 1167 if (sysinfo(SI_HW_PROVIDER, buf, len) == -1) { 1168 ec_os_errgrp_ = ERRNO_UNIX; ec_os_errno_ = errno; errno = 0; 1169 return -1; 1170 } 1171 bufp = buf + strlen(buf); 1172 *bufp++ = '#'; 1173 if (sysinfo(SI_HW_SERIAL, bufp, len-(bufp-buf)) == -1) { 1174 ec_os_errgrp_ = ERRNO_UNIX; ec_os_errno_ = errno; errno = 0; 1175 return -1; 1176 } 1177 1178#else 1179#ifdef HAVE_SIOCGIFHWADDR 1180 1181 /* 1182 * This gets (an) Ethernet adapter hardware address 1183 */ 1184 1185 int sockFd; 1186 struct ifreq req; 1187 struct sockaddr_in *sin; 1188 1189#ifndef IPPROTO_IP 1190#define IPPROTO_IP 0 1191#endif 1192 1193 sockFd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); 1194 1195 memset(&req, 0, sizeof(struct ifreq)); 1196 strcpy(req.ifr_name, "eth0"); 1197 1198 if (ioctl(sockFd, SIOCGIFHWADDR ,&req) == 0) 1199 { 1200 sprintf(buf, "L#%02x%02x%02x%02x%02x%02x", 1201 req.ifr_hwaddr.sa_data[0]&0xff, req.ifr_hwaddr.sa_data[1]&0xff, 1202 req.ifr_hwaddr.sa_data[2]&0xff, req.ifr_hwaddr.sa_data[3]&0xff, 1203 req.ifr_hwaddr.sa_data[4]&0xff, req.ifr_hwaddr.sa_data[5]&0xff); 1204 } 1205 else /* use gethostid() if it didn't work */ 1206 { 1207 (void) sprintf(buf, "H#%d", gethostid()); 1208 } 1209 close(sockFd); 1210 1211 1212#else 1213 1214 (void) sprintf(buf, "H#%d", gethostid()); 1215 1216#endif 1217#endif 1218#endif 1219 1220 return strlen(buf); 1221} 1222 1223 1224int 1225ec_gethostname(char *buf, int size) /* sets ec_os_errno_/errgrp_ on failure */ 1226{ 1227 int i; 1228 struct hostent *hp; 1229 1230 1231#if defined(HAVE_GETHOSTNAME) 1232 if (gethostname(buf, size)) { 1233# ifdef _WIN32 1234 ec_os_errgrp_ = ERRNO_WIN32; ec_os_errno_ = GetLastError(); 1235# else 1236 ec_os_errgrp_ = ERRNO_UNIX; ec_os_errno_ = errno; errno = 0; 1237# endif 1238 return -1; 1239 } 1240#else 1241# if defined(HAVE_SYSINFO) && defined(HAVE_SYS_SYSTEMINFO_H) 1242/* Linux has sysinfo(), but not same interface or sys/systeminfo.h */ 1243 if (sysinfo(SI_HOSTNAME, buf, size) == -1) { 1244 ec_os_errgrp_ = ERRNO_UNIX; ec_os_errno_ = errno; errno = 0; 1245 return -1; 1246 } 1247# else 1248 /* assume uname is defined */ 1249 struct utsname utsn; 1250 1251 if (uname(&utsn) <= -1) { 1252# ifdef _WIN32 1253 ec_os_errgrp_ = ERRNO_WIN32; ec_os_errno_ = GetLastError(); 1254# else 1255 ec_os_errgrp_ = ERRNO_UNIX; ec_os_errno_ = errno; errno = 0; 1256# endif 1257 return -1; 1258 } 1259 strncpy(buf, utsn.nodename, size); 1260# endif 1261#endif 1262 1263#ifdef sun4_0 1264/* There is a bug with the Sun4 static C library version of gethostbyname(): 1265 * it seems to strip the full hostname (with dots) and return the single 1266 * component (without dots), rather than the other way round 1267 */ 1268 hp = NULL; 1269#elif defined(BARRELFISH) 1270 hp = NULL; 1271#else 1272 hp = gethostbyname(buf); 1273#endif 1274#if defined(BARRELFISH) 1275 buf = "barrelfish.local"; 1276#else 1277 if (hp != NULL) { 1278 strncpy(buf, hp->h_name, size); 1279 } 1280#endif 1281 1282 return strlen(buf); 1283} 1284 1285 1286void 1287ec_sleep(double seconds) 1288{ 1289#ifdef _WIN32 1290 (void) SleepEx((DWORD) (seconds*1000.0), TRUE); 1291#else 1292#ifdef HAVE_SELECT 1293 struct timeval sleep_time; 1294 fd_set rs, ws, es; 1295 1296 sleep_time.tv_sec = (long) seconds; 1297 sleep_time.tv_usec = (long) ((seconds - floor(seconds)) * 1000000.0); 1298 FD_ZERO(&rs); 1299 FD_ZERO(&ws); 1300 FD_ZERO(&es); 1301 (void) select(0, &rs, &ws, &es, &sleep_time); 1302#else 1303#ifdef HAVE_SLEEP 1304 (void) sleep((unsigned) seconds); 1305#endif 1306#endif 1307#endif 1308} 1309 1310void 1311ec_bad_exit(char *msg) 1312{ 1313#ifdef _WIN32 1314 FatalAppExit(0, msg); 1315#else 1316 (void) write(2, msg, strlen(msg)); 1317 (void) write(2, "\n", 1); 1318 exit(-1); 1319#endif 1320} 1321 1322#ifndef HAVE_STRERROR 1323char * 1324strerror(int n) 1325{ 1326 extern int sys_nerr; 1327 extern char *sys_errlist[]; 1328 if (n < 0 || n >= sys_nerr) 1329 return (char *) 0; 1330 return sys_errlist[n]; 1331} 1332#endif 1333 1334char * 1335ec_os_err_string(int err, int grp, char *buf, int size) 1336{ 1337#ifdef _WIN32 1338 switch (grp) 1339 { 1340 case ERRNO_WIN32: 1341 if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 1342 0, (LPTSTR) buf, size, NULL)) 1343 { 1344 sprintf(buf, "Windows error %d", err); 1345 } 1346 return buf; 1347 1348 case ERRNO_UNIX: 1349#endif 1350 if (err == 0) 1351 return ""; 1352 else 1353 { 1354 char * message = strerror(err); 1355 if (message) 1356 return message; 1357 sprintf(buf, "Unix error %d", err); 1358 return buf; 1359 } 1360#ifdef _WIN32 1361 } 1362#endif 1363} 1364 1365#ifdef _WIN32 1366int 1367ec_getch_raw(int unit) 1368{ 1369 return _getch(); 1370} 1371 1372int 1373ec_putch_raw(int c) 1374{ 1375 _putch(c); 1376 return 0; 1377} 1378#endif 1379 1380 1381/* 1382 * On SunOS4 with gcc version 2.95.3 20010315 (release) at least, strcmp() 1383 * seems to have a bug and accesses memory beyond the end of the string s2. 1384 * This causes segmentation violations when the string happens to be right 1385 * at the end of mapped memory. 1386 */ 1387 1388#ifdef sun4_0 1389int strcmp(char *s1, char *s2) 1390{ 1391 while (*s1 == *s2) { 1392 if (!*s1) return 0; 1393 ++s1; ++s2; 1394 } 1395 return *s1 - *s2; 1396} 1397#endif 1398 1399 1400/*---------------------------------------------------------------------- 1401 * Simple thread interface 1402 *----------------------------------------------------------------------*/ 1403 1404#ifdef _WIN32 1405 1406typedef struct { 1407 HANDLE thread_handle; 1408 1409 /* this event signals that a function and data has been supplied */ 1410 HANDLE start_event; 1411 1412 /* this event signals that the function has terminated */ 1413 HANDLE done_event; 1414 1415 /* the function to execute, NULL signals termination request */ 1416 int (* volatile fun)(void *); 1417 1418 /* argument for the function call: valid iff fun!=NULL */ 1419 void * volatile data; 1420 1421 /* result of the function call: valid iff fun==NULL */ 1422 int volatile result; 1423 1424} thread_data; 1425 1426 1427/* The general thread procedure */ 1428 1429static 1430DWORD WINAPI 1431ec_fun_thread(thread_data *desc) 1432{ 1433 for(;;) 1434 { 1435 DWORD res; 1436 1437 /* wait for a SetEvent() */ 1438 res = WaitForSingleObject(desc->start_event, INFINITE); 1439 if (res == WAIT_FAILED) 1440 ec_bad_exit("ECLiPSe: thread wait failed"); 1441 1442 if (!desc->fun) /* no function = termination request */ 1443 ExitThread(1); 1444 1445 desc->result = (*desc->fun)(desc->data); /* run it ... */ 1446 desc->fun = NULL; /* ... and signal stopping */ 1447 1448 if (!SetEvent(((thread_data*)desc)->done_event)) 1449 { 1450 ec_bad_exit("ECLiPSe: thread stopping signalling failed"); 1451 } 1452 } 1453 return 1; 1454} 1455 1456void * 1457ec_make_thread(void) 1458{ 1459 DWORD thread_id; 1460 thread_data *desc = malloc(sizeof(thread_data)); 1461 1462 desc->fun = NULL; 1463 desc->start_event = CreateEvent(NULL, FALSE, FALSE, NULL); 1464 if (!desc->start_event) 1465 { 1466 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1467 return NULL; 1468 } 1469 desc->done_event = CreateEvent(NULL, TRUE, FALSE, NULL); 1470 if (!desc->done_event) 1471 { 1472 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1473 return NULL; 1474 } 1475 desc->thread_handle = CreateThread(NULL, 0, 1476 (LPTHREAD_START_ROUTINE) ec_fun_thread, 1477 (LPVOID) desc, 0, &thread_id); 1478 if (!desc->thread_handle) 1479 { 1480 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1481 return NULL; 1482 } 1483#if 0 1484 /* 1485 * The following line should not be needed, but we had problems 1486 * with the thread not being started otherwise - Windows bug? 1487 */ 1488 ResumeThread(desc->thread_handle); 1489#endif 1490 return (void *) desc; 1491} 1492 1493 1494/* 1495 * Test whether the thread has finished (without waiting). 1496 * Returns: 1 if thread stopped, 0 otherwise 1497 * If stopped, *result contains the result of the thread computation> 1498 */ 1499 1500int 1501ec_thread_stopped(void *desc, int *result) 1502{ 1503 if (!((thread_data*)desc)->fun) 1504 { 1505 *result = ((thread_data*)desc)->result; 1506 return 1; 1507 } 1508 return 0; 1509} 1510 1511 1512/* 1513 * Wait for the thread to finish (max timeout milliseconds) 1514 * timeout == -1: wait indefinitely 1515 * timeout == 0: don't wait 1516 * timeout > 0: wait timeout milliseconds 1517 * Returns: 1 if thread stopped, 0 otherwise 1518 * If stopped, *result contains the result of the thread computation> 1519 */ 1520 1521int 1522ec_thread_wait(void *desc, int *result, int timeout) 1523{ 1524 if (timeout != 0) 1525 { 1526 switch(WaitForSingleObject(((thread_data*)desc)->done_event, 1527 timeout > 0 ? (DWORD) timeout : INFINITE)) 1528 { 1529 case WAIT_OBJECT_0: /* stopping was signalled */ 1530 case WAIT_TIMEOUT: /* timeout occurred */ 1531 break; 1532 1533 default: 1534 ec_bad_exit("ECLiPSe: thread wait failed"); 1535 } 1536 } 1537 return ec_thread_stopped(desc, result); 1538} 1539 1540int 1541ec_start_thread(void *desc, int (*fun)(void *), void *data) 1542{ 1543 if (((thread_data*)desc)->fun) 1544 return 0; /* thread still busy */ 1545 1546 if (!ResetEvent(((thread_data*)desc)->done_event)) 1547 { 1548 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1549 return 0; 1550 } 1551 ((thread_data*)desc)->data = data; 1552 ((thread_data*)desc)->fun = fun; 1553 if (!SetEvent(((thread_data*)desc)->start_event)) 1554 { 1555 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1556 return 0; 1557 } 1558 return 1; 1559} 1560 1561/* 1562 * Terminate the thread. This should only be done when already stopped. 1563 * Returns: 1 if cleanly terminated, 0 if forcibly terminated, -1 error 1564 */ 1565int 1566ec_thread_terminate(void *desc, int timeout) 1567{ 1568 int result; 1569 DWORD thread_exit_code = 0; 1570 1571 if (ec_thread_stopped(desc, &result)) 1572 { 1573 /* restart the thread with NULL function: leads to termination */ 1574 ((thread_data*)desc)->fun = 0; 1575 if (!SetEvent(((thread_data*)desc)->start_event)) 1576 { 1577 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1578 return -1; 1579 } 1580 } 1581 else 1582 { 1583 /* still running, terminate forcibly */ 1584 if (!TerminateThread(((thread_data*)desc)->thread_handle, 0)) 1585 { 1586 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1587 return -1; 1588 } 1589 } 1590 switch(WaitForSingleObject(((thread_data*)desc)->thread_handle, timeout > 0 ? (DWORD)timeout : INFINITE)) 1591 { 1592 case WAIT_OBJECT_0: /* termination was signalled */ 1593 if (!GetExitCodeThread(((thread_data*)desc)->thread_handle, &thread_exit_code)) 1594 { 1595 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1596 return -1; 1597 } 1598 /*thread_exit_code is 0 or 1 */ 1599 break; 1600 1601 default: 1602 case WAIT_TIMEOUT: /* timeout occurred, terminate forcibly */ 1603 if (!TerminateThread(((thread_data*)desc)->thread_handle, 0)) 1604 { 1605 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1606 return -1; 1607 } 1608 /* thread_exit_code is 0, don't bother to wait */ 1609 break; 1610 1611 case WAIT_FAILED: 1612 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1613 return -1; 1614 } 1615 1616 if (!CloseHandle(((thread_data*)desc)->thread_handle) || 1617 !CloseHandle(((thread_data*)desc)->start_event) || 1618 !CloseHandle(((thread_data*)desc)->done_event)) 1619 { 1620 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1621 return -1; 1622 } 1623 free(desc); 1624 return thread_exit_code; /* 0 or 1 */ 1625} 1626 1627#endif 1628 1629 1630/*---------------------------------------------------------------------- 1631 * Timers 1632 *----------------------------------------------------------------------*/ 1633#ifdef _WIN32 1634 1635/* 1636 * Windows doesn't seem to have timers that you can ask for the 1637 * remaining time. We therefore store the due time ourselves. 1638 * The DWORDs are all in milliseconds, the LONGLONG is 100 ns units. 1639 */ 1640typedef struct { 1641 HANDLE thread_handle; /* must be first */ 1642 1643/* signals that the new_xxx settings are valid and should be accepted */ 1644 HANDLE time_set_event; 1645 1646/* signals that new settings have been accepted and old_xxx are valid */ 1647 HANDLE time_accept_event; 1648 1649/* input (w for main, r for thread) */ 1650 DWORD new_first; /* first interval (ms) */ 1651 DWORD new_ivl; /* future intervals (ms) */ 1652 void (*new_callback)(long); /* callback function ... */ 1653 long new_cb_arg; /* ... and its argument */ 1654 int terminate_req; /* request to terminate alarm thread */ 1655 1656/* output ( w for thread, r for main) */ 1657 DWORD old_remain; /* remaining time when stopped (ms) */ 1658 DWORD old_ivl; /* old interval setting (ms) */ 1659 1660/* status (w for thread, r for main) */ 1661 int running; /* set while timer running */ 1662 1663/* local (r/w for thread) */ 1664 LONGLONG active_due; /* current due time (100 ns FILETIME) */ 1665 DWORD active_ivl; /* current future intervals (ms) */ 1666 void (*active_callback)(long); /* current callback function ... */ 1667 long active_cb_arg; /* ... and its argument */ 1668 1669} timer_thread; 1670 1671volatile timer_thread alarm_thread = { /*thread_handle*/ NULL }; 1672 1673 1674/* The timer thread procedure */ 1675 1676DWORD WINAPI 1677ec_alarm_thread(timer_thread *desc) 1678{ 1679 DWORD next_timeout = INFINITE; 1680 1681 for(;;) 1682 { 1683 DWORD res; 1684 FILETIME now_time_ft; 1685 LARGE_INTEGER now_time; 1686 1687 res = WaitForSingleObject(desc->time_set_event, next_timeout); 1688 if (res == WAIT_FAILED) 1689 { 1690 ec_bad_exit("ECLiPSe: timer thread WaitForSingleObject() failed"); 1691 } 1692 1693 GetSystemTimeAsFileTime(&now_time_ft); 1694 now_time.LowPart = now_time_ft.dwLowDateTime; 1695 now_time.HighPart = now_time_ft.dwHighDateTime; 1696 1697 /* 1698 * Check whether the active timer has expired and do the callback 1699 * if so. Then either cancel or schedule the next interval. 1700 */ 1701 if (desc->running) 1702 { 1703 if (now_time.QuadPart >= desc->active_due) 1704 { 1705 /* the alarm is due */ 1706 (*desc->active_callback)(desc->active_cb_arg); 1707 if (desc->active_ivl) 1708 { 1709 /* schedule the next interval */ 1710 desc->active_due = now_time.QuadPart + (LONGLONG)desc->active_ivl*10000; 1711 desc->running = 1; 1712 next_timeout = desc->active_ivl; 1713 } 1714 else 1715 { 1716 /* nothing more to do */ 1717 desc->active_due = 0; 1718 desc->active_ivl = 0; 1719 desc->running = 0; 1720 next_timeout = INFINITE; 1721 } 1722 } 1723 else /* timed out too early, or SetEvent */ 1724 { 1725 desc->running = 1; 1726 next_timeout = (desc->active_due - now_time.QuadPart)/10000; 1727 if (next_timeout == 0) next_timeout = 1; 1728 } 1729 } 1730 1731 /* 1732 * If we had a timer_set_event, pick up 1733 * the new times and return the old ones. 1734 */ 1735 if (res == WAIT_OBJECT_0) 1736 { 1737 if (desc->terminate_req) 1738 { 1739 break; /* same as ExitThread(1); */ 1740 } 1741 else 1742 { 1743 desc->old_remain = desc->running ? next_timeout : 0; 1744 desc->old_ivl = desc->active_ivl; 1745 1746 if (desc->new_first) /* change settings */ 1747 { 1748 desc->active_due = now_time.QuadPart + (LONGLONG)desc->new_first*10000; 1749 desc->active_ivl = desc->new_ivl; 1750 desc->active_callback = desc->new_callback; 1751 desc->active_cb_arg = desc->new_cb_arg; 1752 desc->running = 1; 1753 next_timeout = desc->new_first; 1754 } 1755 else /* clear settings */ 1756 { 1757 desc->active_due = 0; 1758 desc->active_ivl = 0; 1759 desc->running = 0; 1760 next_timeout = INFINITE; 1761 } 1762 /* indicate acceptance */ 1763 if (!SetEvent(desc->time_accept_event)) 1764 { 1765 ec_bad_exit("ECLiPSe: timer thread SetEvent() failed"); 1766 } 1767 } 1768 } 1769 } 1770 return 1; 1771} 1772 1773 1774int 1775ec_set_alarm( 1776 double first, /* new initial interval (0: stop timer) */ 1777 double interv, /* new periodic interval (0: one shot) */ 1778 void (*callback)(long), /* callback function ... */ 1779 long cb_arg, /* ... and its argument */ 1780 double *premain, /* return time to next timeout */ 1781 double *old_interv) /* return previous interval setting */ 1782{ 1783 if (!alarm_thread.thread_handle) /* create thread if not yet there */ 1784 { 1785 DWORD thread_id; 1786 alarm_thread.terminate_req = 0; 1787 alarm_thread.running = 0; 1788 alarm_thread.time_set_event = CreateEvent(NULL, FALSE, FALSE, NULL); 1789 if (!alarm_thread.time_set_event) 1790 { 1791 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1792 return 0; 1793 } 1794 alarm_thread.time_accept_event = CreateEvent(NULL, FALSE, FALSE, NULL); 1795 if (!alarm_thread.time_accept_event) 1796 { 1797 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1798 return 0; 1799 } 1800 alarm_thread.thread_handle = CreateThread(NULL, 0, 1801 (LPTHREAD_START_ROUTINE) ec_alarm_thread, 1802 (LPVOID) &alarm_thread, 0, &thread_id); 1803 if (!alarm_thread.thread_handle) 1804 { 1805 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1806 return 0; 1807 } 1808 } 1809 1810 /* write new parameters into the descriptor */ 1811 alarm_thread.new_first = (DWORD) (first*1000.0); 1812 if (alarm_thread.new_first==0 && first>0.0) alarm_thread.new_first = 1; 1813 alarm_thread.new_ivl = (DWORD) (interv*1000.0); 1814 if (alarm_thread.new_ivl==0 && interv>0.0) alarm_thread.new_ivl = 1; 1815 alarm_thread.new_callback = callback; 1816 alarm_thread.new_cb_arg = cb_arg; 1817 1818 if (!SetEvent(alarm_thread.time_set_event)) 1819 { 1820 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1821 return 0; 1822 } 1823 1824 /* wait for thread to accept new times and return old ones */ 1825 switch (WaitForSingleObject(alarm_thread.time_accept_event, 10000)) 1826 { 1827 case WAIT_FAILED: 1828 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1829 return 0; 1830 1831 default: 1832 Set_Sys_Errno(ERROR_TIMEOUT,ERRNO_WIN32); 1833 return 0; 1834 1835 case WAIT_OBJECT_0: 1836 if (premain) *premain = alarm_thread.old_remain / 1000.0; 1837 if (old_interv) *old_interv = alarm_thread.old_ivl / 1000.0; 1838 return 1; 1839 } 1840} 1841 1842 1843/* 1844 * Terminate the alarm thread. 1845 * Returns: 1 if cleanly terminated, 0 if forcibly terminated, -1 error 1846 */ 1847int 1848ec_terminate_alarm() 1849{ 1850 DWORD thread_exit_code = 0; 1851 1852 if (!alarm_thread.thread_handle) 1853 return 0; 1854 1855 /* send a termination request to the thread */ 1856 alarm_thread.terminate_req = 1; 1857 if (!SetEvent(alarm_thread.time_set_event)) 1858 { 1859 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1860 return -1; 1861 } 1862 1863 /* wait for termination */ 1864 switch(WaitForSingleObject(alarm_thread.thread_handle, 3000)) 1865 { 1866 case WAIT_OBJECT_0: /* termination was signalled */ 1867 if (!GetExitCodeThread(alarm_thread.thread_handle, &thread_exit_code)) 1868 { 1869 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1870 return -1; 1871 } 1872 /* thread_exit_code is 0 or 1 */ 1873 break; 1874 1875 default: 1876 case WAIT_TIMEOUT: /* timeout occurred, terminate forcibly */ 1877 if (!TerminateThread(alarm_thread.thread_handle, 0)) 1878 { 1879 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1880 return -1; 1881 } 1882 /* thread_exit_code is 0, don't bother to wait */ 1883 break; 1884 1885 case WAIT_FAILED: 1886 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1887 return -1; 1888 } 1889 1890 if (!CloseHandle(alarm_thread.thread_handle) || 1891 !CloseHandle(alarm_thread.time_set_event) || 1892 !CloseHandle(alarm_thread.time_accept_event)) 1893 { 1894 Set_Sys_Errno(GetLastError(),ERRNO_WIN32); 1895 return -1; 1896 } 1897 1898 alarm_thread.thread_handle = NULL; 1899 return thread_exit_code; /* 0 or 1 */ 1900} 1901 1902 1903#else 1904#ifdef HAVE_PTHREAD_H 1905 1906/* 1907 * Unix pthreads version 1908 */ 1909 1910typedef struct { 1911 pthread_t thread_handle; /* must be first */ 1912 pthread_mutex_t mutex; /* mutex for the two conds */ 1913 1914/* signals that the new_xxx settings are valid and should be accepted */ 1915 pthread_cond_t time_set_event; 1916 1917/* signals that new settings have been accepted and old_xxx are valid */ 1918 pthread_cond_t time_accept_event; 1919 1920/* input (w for main, r for thread) */ 1921 double volatile new_first; /* first interval (s) */ 1922 double volatile new_ivl; /* future intervals (s) */ 1923 void (* volatile new_callback)(long); /* callback function ... */ 1924 long volatile new_cb_arg; /* ... and its argument */ 1925 int volatile terminate_req; /* request to terminate alarm thread */ 1926 1927/* output ( w for thread, r for main) */ 1928 double volatile old_remain; /* remaining time when stopped (s) */ 1929 double volatile old_ivl; /* old interval setting (s) */ 1930 1931/* status (w for thread, r for main) */ 1932 int volatile running; /* set while timer running */ 1933 1934/* local (r/w for thread) */ 1935 double active_due; /* current due time (s since epoch) */ 1936 double active_ivl; /* current future intervals (s) */ 1937 void (*active_callback)(long); /* current callback function ... */ 1938 long active_cb_arg; /* ... and its argument */ 1939 1940} timer_thread; 1941 1942timer_thread alarm_thread = { /*thread_handle*/ (pthread_t) NULL }; 1943 1944 1945/* The timer thread procedure */ 1946 1947void * 1948ec_alarm_thread(timer_thread *desc) 1949{ 1950 pthread_mutex_lock(&desc->mutex); 1951 pthread_cond_signal(&desc->time_accept_event); 1952 for(;;) 1953 { 1954 int res; 1955 struct timeval now_timeval; 1956 double now_time; 1957 1958 if (desc->running) 1959 { 1960 struct timespec next_timeout_spec; 1961 next_timeout_spec.tv_sec = (time_t) desc->active_due; 1962 next_timeout_spec.tv_nsec = (desc->active_due - next_timeout_spec.tv_sec) * 1e9; 1963 res = pthread_cond_timedwait(&desc->time_set_event, &desc->mutex, &next_timeout_spec); 1964 } 1965 else 1966 { 1967 res = pthread_cond_wait(&desc->time_set_event, &desc->mutex); 1968 } 1969 if (res && res != ETIMEDOUT) 1970 { 1971 pthread_mutex_unlock(&desc->mutex); 1972 ec_bad_exit("ECLiPSe: timer thread WaitForSingleObject() failed"); 1973 } 1974 1975 gettimeofday(&now_timeval, NULL); 1976 now_time = (double)now_timeval.tv_sec + (double)now_timeval.tv_usec/1000000.0; 1977 1978 /* 1979 * Check whether the active timer has expired and do the callback 1980 * if so. Then either cancel or schedule the next interval. 1981 */ 1982 if (desc->running) 1983 { 1984 if (now_time >= desc->active_due) 1985 { 1986 /* the alarm is due */ 1987 (*desc->active_callback)(desc->active_cb_arg); 1988 if (desc->active_ivl > 0.0) 1989 { 1990 /* schedule the next interval */ 1991 desc->active_due = now_time + desc->active_ivl; 1992 desc->running = 1; 1993 } 1994 else 1995 { 1996 /* nothing more to do */ 1997 desc->active_due = 0.0; 1998 desc->active_ivl = 0.0; 1999 desc->running = 0; 2000 } 2001 } 2002 /* else timed out too early, or SetEvent */ 2003 } 2004 2005 /* 2006 * If we had a timer_set_event, pick up 2007 * the new times and return the old ones. 2008 */ 2009 if (res == 0) 2010 { 2011 if (desc->terminate_req) 2012 { 2013 break; /* same as pthread_exit(1); */ 2014 } 2015 else 2016 { 2017 desc->old_remain = desc->running ? desc->active_due - now_time : 0.0; 2018 desc->old_ivl = desc->active_ivl; 2019 2020 if (desc->new_first) /* change settings */ 2021 { 2022 desc->active_due = now_time + desc->new_first; 2023 desc->active_ivl = desc->new_ivl; 2024 desc->active_callback = desc->new_callback; 2025 desc->active_cb_arg = desc->new_cb_arg; 2026 desc->running = 1; 2027 } 2028 else /* clear settings */ 2029 { 2030 desc->active_due = 0; 2031 desc->active_ivl = 0; 2032 desc->running = 0; 2033 } 2034 /* indicate acceptance */ 2035 pthread_cond_signal(&desc->time_accept_event); 2036 } 2037 } 2038 } 2039 pthread_mutex_unlock(&desc->mutex); 2040 return (void*) 1; 2041} 2042 2043 2044int 2045ec_set_alarm( 2046 double first, /* new initial interval (0: stop timer) */ 2047 double interv, /* new periodic interval (0: one shot) */ 2048 void (*callback)(long), /* callback function ... */ 2049 long cb_arg, /* ... and its argument */ 2050 double *premain, /* return time to next timeout */ 2051 double *old_interv) /* return previous interval setting */ 2052{ 2053 int res; 2054 if (!alarm_thread.thread_handle) /* create thread if not yet there */ 2055 { 2056 alarm_thread.terminate_req = 0; 2057 alarm_thread.running = 0; 2058 if (pthread_mutex_init(&alarm_thread.mutex, NULL) 2059 || pthread_cond_init(&alarm_thread.time_set_event, NULL) 2060 || pthread_cond_init(&alarm_thread.time_accept_event, NULL) 2061 || pthread_mutex_lock(&alarm_thread.mutex) 2062 || pthread_create(&alarm_thread.thread_handle, NULL, 2063 (void*(*)(void*))ec_alarm_thread, (void*) &alarm_thread) 2064 /* wait for ec_alarm_thread to be ready */ 2065 || pthread_cond_wait(&alarm_thread.time_accept_event, &alarm_thread.mutex) 2066 ) 2067 { 2068 pthread_mutex_unlock(&alarm_thread.mutex); 2069 Set_Sys_Errno(errno, ERRNO_UNIX); 2070 return 0; 2071 } 2072 } 2073 else 2074 { 2075 pthread_mutex_lock(&alarm_thread.mutex); 2076 } 2077 2078 /* write new parameters into the descriptor */ 2079 alarm_thread.new_first = (0.0 < first && first < 1.0e-6) ? 1.0e-6 : first; 2080 alarm_thread.new_ivl = (0.0 < interv && interv < 1.0e-6) ? 1.0e-6 : interv; 2081 alarm_thread.new_callback = callback; 2082 alarm_thread.new_cb_arg = cb_arg; 2083 2084 pthread_cond_signal(&alarm_thread.time_set_event); 2085 2086 /* wait for thread to accept new times and return old ones */ 2087 res = pthread_cond_wait(&alarm_thread.time_accept_event, &alarm_thread.mutex); 2088 pthread_mutex_unlock(&alarm_thread.mutex); 2089 if (res) 2090 { 2091 Set_Sys_Errno(errno, ERRNO_UNIX); 2092 return 0; 2093 } 2094 2095 if (premain) *premain = alarm_thread.old_remain; 2096 if (old_interv) *old_interv = alarm_thread.old_ivl; 2097 return 1; 2098} 2099 2100 2101/* 2102 * Terminate the alarm thread. 2103 * Returns: 1 if cleanly terminated, 0 if forcibly terminated, -1 error 2104 */ 2105int 2106ec_terminate_alarm() 2107{ 2108 void *thread_exit_code = NULL; 2109 2110 if (!alarm_thread.thread_handle) 2111 return 0; 2112 2113 /* send a termination request to the thread */ 2114 alarm_thread.terminate_req = 1; 2115 pthread_mutex_lock(&alarm_thread.mutex); 2116 pthread_cond_signal(&alarm_thread.time_set_event); 2117 pthread_mutex_unlock(&alarm_thread.mutex); 2118 2119 /* wait for termination */ 2120 if (pthread_join(alarm_thread.thread_handle, &thread_exit_code)) 2121 { 2122 Set_Sys_Errno(errno, ERRNO_UNIX); 2123 return -1; 2124 } 2125 2126 pthread_cond_destroy(&alarm_thread.time_set_event); 2127 pthread_cond_destroy(&alarm_thread.time_accept_event); 2128 pthread_mutex_destroy(&alarm_thread.mutex); 2129 alarm_thread.thread_handle = (pthread_t) NULL; 2130 return thread_exit_code ? 1 : 0; /* 0 or 1 */ 2131} 2132 2133#else 2134int ec_terminate_alarm() { return 0; } 2135#endif 2136#endif 2137 2138 2139/*---------------------------------------------------------------------- 2140 * Registry/Environment lookup 2141 * 2142 * Windows: 2143 * look up <name> under 2144 * HKEY_LOCAL_MACHINE\SOFTWARE\IC-Parc\ECLiPSe 2145 * or else 2146 * HKEY_LOCAL_MACHINE\SOFTWARE\IC-Parc\ECLiPSe\<version> 2147 * or else 2148 * as environment variable <name> 2149 * Note that 64 bit Windows keeps two sets of registry entries, for 2150 * 32 and 64 bit applications, so i386_nt and x86_64_nt ECLiPSe 2151 * running on the same machine will not share their registry entries 2152 * 2153 * Unix: 2154 * look up <name> 2155 * as environment variable <name>_<major>_<minor> 2156 * e.g. ECLIPSEDIR_5_10 for version 5.10 2157 * or else 2158 * as environment variable <name> 2159 * e.g. ECLIPSEDIR 2160 * 2161 * return NULL if not found, buffer address otherwise. 2162 * 2163 * A buffer must be provided by the caller. 2164 * buflen is a pointer to the length of the buffer provided, 2165 * it is overwritten with the number of bytes actually returned 2166 * (CAUTION: this size includes a terminating zero if any). 2167 * If this number is greater than the buflen initially provided, 2168 * it is undefined whether any data is returned in the buffer. 2169 *----------------------------------------------------------------------*/ 2170 2171#ifdef _WIN32 2172 2173char * 2174ec_env_lookup(char *name, char *buf, int *buflen) 2175{ 2176 HKEY key1, key2; 2177 LONG err; 2178 DWORD vtype, buflen_dw; 2179 char *res; 2180 int len; 2181 2182 err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\IC-Parc\\ECLiPSe", 0, KEY_READ, &key1); 2183 if (err != ERROR_SUCCESS) 2184 { 2185 goto _try_env_; 2186 } 2187 err = RegOpenKeyEx(key1, ec_version, 0, KEY_READ, &key2); 2188 if (err != ERROR_SUCCESS) 2189 { 2190 (void) RegCloseKey(key1); 2191 goto _try_env_; 2192 } 2193 (void) RegCloseKey(key1); 2194 buflen_dw = *buflen; 2195 err = RegQueryValueEx(key2, name, NULL, &vtype, buf, &buflen_dw); 2196 *buflen = buflen_dw; 2197 (void) RegCloseKey(key2); 2198 if (!(err == ERROR_SUCCESS || err == ERROR_MORE_DATA)) 2199 { 2200 goto _try_env_; 2201 } 2202 return buf; 2203 2204_try_env_: 2205 len = GetEnvironmentVariable(name, buf, *buflen); 2206 /* On Windows, we can't tell the difference between an unset variable 2207 * and an empty string! Empty strings therefore look like unset. */ 2208 if (len == 0) 2209 return NULL; 2210 /* If buffer was large enough, len is string size without terminator, 2211 * otherwise required buffer size with terminator! */ 2212 *buflen = len < *buflen ? len + 1 : len; 2213 return buf; 2214} 2215 2216#else 2217 2218char * 2219ec_env_lookup(char *name, char *buf, int *buflen) 2220{ 2221 int i, len; 2222 char *res, *from, *to; 2223 char *vname = (char *) malloc(strlen(name)+strlen(ec_version)+2); 2224 2225 /* construct name_X_Y from name and ec_version X.Y */ 2226 for(from=name,to=vname; *from; ++from,++to) 2227 *to = *from; 2228 *to++ = '_'; 2229 for(from=ec_version; *from; ++from,++to) 2230 *to = *from == '.' ? '_' : *from; 2231 *to = 0; 2232 2233 if (!(res = getenv(vname)) && !(res = getenv(name))) 2234 { 2235 free(vname); 2236 Set_Sys_Errno(0, ERRNO_UNIX); 2237 return NULL; 2238 } 2239 free(vname); 2240 len = strlen(res)+1; 2241 if (len > *buflen) 2242 strncpy(buf, res, *buflen); 2243 else 2244 strncpy(buf, res, len); 2245 *buflen = len; 2246 return buf; 2247} 2248 2249#endif 2250