Select Git revision
Callbacks.cpp
Forked from
gmsh / gmsh
Source project has a limited visibility.
-
Christophe Geuzaine authored
This patch fixes an old design flaw in the post-processing module, namely that we used a list of Post_View objects instead of a list of pointers to Post_View objects in CTX.post.list. This had many annoying consequences, in particular the fact that we needed to be extra careful every time the list was reallocated (as pointers to the list elements would become invalid). I tried very hard to change the code everywhere it should be changed, but I might have missed something. Please let me know if you see anything suspicious (like a crash when you duplicate/remove/combine/... post-processing views).
Christophe Geuzaine authoredThis patch fixes an old design flaw in the post-processing module, namely that we used a list of Post_View objects instead of a list of pointers to Post_View objects in CTX.post.list. This had many annoying consequences, in particular the fact that we needed to be extra careful every time the list was reallocated (as pointers to the list elements would become invalid). I tried very hard to change the code everywhere it should be changed, but I might have missed something. Please let me know if you see anything suspicious (like a crash when you duplicate/remove/combine/... post-processing views).
OS.cpp 12.27 KiB
// Gmsh - Copyright (C) 1997-2013 C. Geuzaine, J.-F. Remacle
//
// See the LICENSE.txt file for license information. Please report all
// bugs and problems to the public mailing list <gmsh@geuz.org>.
// This file contains a bunch of functions that depend on OS-dependent
// features and/or system calls
// these are available on all OSes
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <time.h>
#include <math.h>
#include "GmshConfig.h"
#include "StringUtils.h"
#if !defined(WIN32) || defined(__CYGWIN__)
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#endif
#if defined(WIN32)
#include <windows.h>
#include <process.h>
#include <psapi.h>
#include <io.h>
#include <direct.h>
#include <fcntl.h>
#include <iostream>
#include <fstream>
#endif
#if defined(__APPLE__)
#define RUSAGE_SELF 0
#define RUSAGE_CHILDREN -1
#endif
#include "GmshMessage.h"
#if defined(WIN32) && !defined(__CYGWIN__)
// UTF8 utility routines borrowed from FLTK
static unsigned utf8decode(const char* p, const char* end, int* len)
{
static unsigned short cp1252[32] = {
0x20ac, 0x0081, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008d, 0x017d, 0x008f,
0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x009d, 0x017e, 0x0178
};
unsigned char c = *(unsigned char*)p;
if (c < 0x80) {
if (len) *len = 1;
return c;
} else if (c < 0xa0) {
if (len) *len = 1;
return cp1252[c-0x80];
} else if (c < 0xc2) {
goto FAIL;
}
if ( (end && p+1 >= end) || (p[1]&0xc0) != 0x80) goto FAIL;
if (c < 0xe0) {
if (len) *len = 2;
return
((p[0] & 0x1f) << 6) +
((p[1] & 0x3f));
} else if (c == 0xe0) {
if (((unsigned char*)p)[1] < 0xa0) goto FAIL;
goto UTF8_3;
} else if (c < 0xf0) {
UTF8_3:
if ( (end && p+2 >= end) || (p[2]&0xc0) != 0x80) goto FAIL;
if (len) *len = 3;
return
((p[0] & 0x0f) << 12) +
((p[1] & 0x3f) << 6) +
((p[2] & 0x3f));
} else if (c == 0xf0) {
if (((unsigned char*)p)[1] < 0x90) goto FAIL;
goto UTF8_4;
} else if (c < 0xf4) {
UTF8_4:
if ( (end && p+3 >= end) || (p[2]&0xc0) != 0x80 || (p[3]&0xc0) != 0x80) goto FAIL;
if (len) *len = 4;
return
((p[0] & 0x07) << 18) +
((p[1] & 0x3f) << 12) +
((p[2] & 0x3f) << 6) +
((p[3] & 0x3f));
} else if (c == 0xf4) {
if (((unsigned char*)p)[1] > 0x8f) goto FAIL; /* after 0x10ffff */
goto UTF8_4;
} else {
FAIL:
if (len) *len = 1;
return c;
}
}
static unsigned utf8toUtf16(const char* src, unsigned srclen,
unsigned short* dst, unsigned dstlen)
{
const char* p = src;
const char* e = src+srclen;
unsigned count = 0;
if (dstlen) for (;;) {
if (p >= e) {dst[count] = 0; return count;}
if (!(*p & 0x80)) { /* ascii */
dst[count] = *p++;
} else {
int len; unsigned ucs = utf8decode(p,e,&len);
p += len;
if (ucs < 0x10000) {
dst[count] = ucs;
} else {
/* make a surrogate pair: */
if (count+2 >= dstlen) {dst[count] = 0; count += 2; break;}
dst[count] = (((ucs-0x10000u)>>10)&0x3ff) | 0xd800;
dst[++count] = (ucs&0x3ff) | 0xdc00;
}
}
if (++count == dstlen) {dst[count-1] = 0; break;}
}
/* we filled dst, measure the rest: */
while (p < e) {
if (!(*p & 0x80)) p++;
else {
int len; unsigned ucs = utf8decode(p,e,&len);
p += len;
if (ucs >= 0x10000) ++count;
}
++count;
}
return count;
}
static wchar_t *wbuf[2] = {NULL, NULL};
static void setwbuf(int i, const char *f)
{
if(i != 0 || i != 1) return;
size_t l = strlen(f);
unsigned wn = utf8toUtf16(f, (unsigned) l, NULL, 0) + 1;
wbuf[i] = (wchar_t*)realloc(wbuf[i], sizeof(wchar_t)*wn);
wn = utf8toUtf16(f, (unsigned) l, (unsigned short *)wbuf[i], wn);
wbuf[i][wn] = 0;
}
#endif
FILE *Fopen(const char* f, const char *mode)
{
#if defined (WIN32) && !defined(__CYGWIN__)
setwbuf(0, f);
setwbuf(1, mode);
return _wfopen(wbuf[0], wbuf[1]);
#else
return fopen(f, mode);
#endif
}
const char *GetEnvironmentVar(const char *var)
{
#if defined(WIN32) && !defined(__CYGWIN__)
const char *tmp = getenv(var);
// Don't accept top dir or anything partially expanded like
// c:\Documents and Settings\%USERPROFILE%, etc.
if(!tmp || !strcmp(tmp, "/") || strstr(tmp, "%") || strstr(tmp, "$"))
return 0;
else
return tmp;
#else
return getenv(var);
#endif
}
const void SetEnvironmentVar(const char *var, const char *val)
{
#if defined(WIN32) && !defined(__CYGWIN__)
_putenv((std::string(var) + "=" + std::string(val)).c_str());
#else
setenv(var, val, 1);
#endif
}
double GetTimeInSeconds()
{
#if defined(WIN32) && !defined(__CYGWIN__)
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
double t = 1.e-7 * 4294967296. * (double)ft.dwHighDateTime +
1.e-7 * (double)ft.dwLowDateTime;
return t;
#else
struct timeval tp;
gettimeofday(&tp, (struct timezone *)0);
double t = (double)tp.tv_sec + 1.e-6 * (double)tp.tv_usec;
return t;
#endif
}
void SleepInSeconds(double s)
{
#if defined(WIN32) && !defined(__CYGWIN__)
Sleep((long)(1.e3 * s));
#else
usleep((long)(1.e6 * s));
#endif
}
static void GetResources(double *s, long *mem)
{
#if defined(WIN32) && !defined(__CYGWIN__)
FILETIME creation, exit, kernel, user;
if(GetProcessTimes(GetCurrentProcess(), &creation, &exit, &kernel, &user)){
*s = 1.e-7 * 4294967296. * (double)user.dwHighDateTime +
1.e-7 * (double)user.dwLowDateTime;
}
PROCESS_MEMORY_COUNTERS info;
GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
*mem = (long)info.PeakWorkingSetSize;
#else
static struct rusage r;
getrusage(RUSAGE_SELF, &r);
*s = (double)r.ru_utime.tv_sec + 1.e-6 * (double)r.ru_utime.tv_usec;
#if defined(__APPLE__)
*mem = (long)r.ru_maxrss;
#else
*mem = (long)(r.ru_maxrss * 1024L);
#endif
#endif
}
void CheckResources()
{
#if !defined (WIN32) || defined(__CYGWIN__)
static struct rlimit r;
getrlimit(RLIMIT_STACK, &r);
// Try to get at least 16 MB of stack. Running with too small a stack
// can cause crashes in the recursive calls (e.g. for tet
// classification in 3D Delaunay)
if(r.rlim_cur < 16 * 1024 * 1024){
Msg::Info("Increasing process stack size (%d kB < 16 MB)", r.rlim_cur / 1024);
r.rlim_cur = r.rlim_max;
setrlimit(RLIMIT_STACK, &r);
}
#endif
}
double Cpu()
{
long mem = 0;
double s = 0.;
GetResources(&s, &mem);
return s;
}
long GetMemoryUsage()
{
long mem = 0;
double s = 0.;
GetResources(&s, &mem);
return mem;
}
int GetProcessId()
{
#if defined(WIN32) && !defined(__CYGWIN__)
return _getpid();
#else
return getpid();
#endif
}
std::string GetHostName()
{
char host[256];
gethostname(host, sizeof(host));
return std::string(host);
}
int UnlinkFile(const std::string &fileName)
{
#if defined(WIN32) && !defined(__CYGWIN__)
setwbuf(0, fileName.c_str());
return _wunlink(wbuf[0]);
#else
return unlink(fileName.c_str());
#endif
}
int StatFile(const std::string &fileName)
{
#if defined(WIN32) && !defined(__CYGWIN__)
struct _stat buf;
setwbuf(0, fileName.c_str());
int ret = _wstat(wbuf[0], &buf);
#else
struct stat buf;
int ret = stat(fileName.c_str(), &buf);
#endif
return ret;
}
int CreateDirectory(const std::string &dirName)
{
#if defined(WIN32) && !defined(__CYGWIN__)
setwbuf(0, dirName.c_str());
if(_wmkdir(wbuf[0])) return 0;
#else
if(mkdir(dirName.c_str(), 0777)) return 0;
#endif
return 1;
}
int KillProcess(int pid)
{
#if defined(WIN32) && !defined(__CYGWIN__)
HANDLE hProc = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
if(!TerminateProcess(hProc, 0)){
CloseHandle(hProc);
return 0;
}
#else
if(kill(pid, 9))
return 0;
#endif
return 1;
}
int SystemCall(const std::string &command, bool blocking)
{
// separate (potential) executable from arguments
std::string exe, args;
std::string::size_type pos = command.find_first_of(" ");
if(pos != std::string::npos){
exe = command.substr(0, pos);
args = command.substr(pos, command.size() - pos);
}
else
exe = command;
// get executable extension
std::vector<std::string> split = SplitFileName(exe);
// do we try to run a .py script or a .exe?
bool isPython = (split[2] == ".py" || split[2] == ".PY");
bool isExe = (split[2] == ".exe" || split[2] == ".EXE");
if(isPython || isExe){
if(StatFile(exe)){
Msg::Error("Unable to open file '%s'", exe.c_str());
return 1;
}
}
#if defined(WIN32) && !defined(__CYGWIN__)
if(isPython){
Msg::Info("Shell opening '%s' with arguments '%s'", exe.c_str(),
args.c_str());
ShellExecute(NULL, (char*)"open", (char*)exe.c_str(),
(char*)args.c_str(), NULL, 0);
}
else{
STARTUPINFO suInfo;
PROCESS_INFORMATION prInfo;
memset(&suInfo, 0, sizeof(suInfo));
suInfo.cb = sizeof(suInfo);
Msg::Info("Calling '%s'", command.c_str());
if(blocking){
CreateProcess(NULL, (char*)command.c_str(), NULL, NULL, FALSE,
NORMAL_PRIORITY_CLASS, NULL, NULL,
&suInfo, &prInfo);
// wait until child process exits.
WaitForSingleObject(prInfo.hProcess, INFINITE);
// close process and thread handles.
CloseHandle(prInfo.hProcess);
CloseHandle(prInfo.hThread);
}
else{
// DETACHED_PROCESS removes the console (useful if the program to launch
// is a console-mode exe)
CreateProcess(NULL, (char*)command.c_str(), NULL, NULL, FALSE,
NORMAL_PRIORITY_CLASS|DETACHED_PROCESS, NULL, NULL,
&suInfo, &prInfo);
}
}
#else
std::string cmd(command);
if(isPython || isExe){
if(access(exe.c_str(), X_OK)){
if(isPython){
Msg::Info("Script '%s' is not executable: running with python", exe.c_str());
cmd = "python " + cmd;
}
else
Msg::Warning("File '%s' is not executable", exe.c_str());
}
else if(split[0].empty()){
// workaround if pwd is not in PATH
cmd = "./" + cmd;
}
}
if(!system(NULL)) {
Msg::Error("Could not find /bin/sh: aborting system call");
return 1;
}
if(!blocking) cmd += " &";
Msg::Info("Calling '%s'", cmd.c_str());
if(!system(cmd.c_str())) return 1;
#endif
return 0;
}
std::string GetCurrentWorkdir()
{
char path[1024];
#if defined(WIN32) && !defined(__CYGWIN__)
if(!_getcwd(path, sizeof(path))) return "";
#else
if(!getcwd(path, sizeof(path))) return "";
#endif
std::string str(path);
// match the convention of SplitFileName that delivers directory path
// ending with a directory separator
#if defined(WIN32)
str.append("\\");
#else
str.append("/");
#endif
return str;
}
void RedirectIOToConsole()
{
#if defined(WIN32) && !defined(__CYGWIN__)
// Win32 GUI apps do not write to the DOS console; make it work again by
// attaching to parent console, which allows to use the DOS shell to work with
// Gmsh on the command line (without this hack, you need to either use a
// better shell (e.g. bash), or compile a /subsystem:console version
if(!AttachConsole(ATTACH_PARENT_PROCESS)) return;
// redirect unbuffered stdout, stdin and stderr to the console
{
intptr_t lStdHandle = (intptr_t)GetStdHandle(STD_OUTPUT_HANDLE);
if(lStdHandle != (intptr_t)INVALID_HANDLE_VALUE){
int hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
if(hConHandle >= 0){
FILE *fp = _fdopen(hConHandle, "w");
if(fp){
*stdout = *fp;
setvbuf(stdout, NULL, _IONBF, 0);
}
}
}
}
{
intptr_t lStdHandle = (intptr_t)GetStdHandle(STD_INPUT_HANDLE);
if(lStdHandle != (intptr_t)INVALID_HANDLE_VALUE){
int hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
if(hConHandle >= 0){
FILE *fp = _fdopen(hConHandle, "r");
if(fp){
*stdin = *fp;
setvbuf(stdin, NULL, _IONBF, 0);
}
}
}
}
{
intptr_t lStdHandle = (intptr_t)GetStdHandle(STD_ERROR_HANDLE);
if(lStdHandle != (intptr_t)INVALID_HANDLE_VALUE){
int hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
if(hConHandle >= 0){
FILE *fp = _fdopen(hConHandle, "w");
if(fp){
*stderr = *fp;
setvbuf(stderr, NULL, _IONBF, 0);
}
}
}
}
// make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console
// as well
std::ios::sync_with_stdio();
#endif
}