static foreign_t pl_group_info(term_t group, term_t info) { int gid; struct group grp, *pgrp; char buf[1000]; char *name; term_t members = PL_new_term_ref(); term_t tail = PL_copy_term_ref(members); term_t head = PL_new_term_ref(); char **memp; if ( PL_get_integer(group, &gid) ) { again1: errno = 0; if ( getgrgid_r(gid, &grp, buf, sizeof(buf), &pgrp) != 0 ) { if ( errno == EINTR ) { if ( PL_handle_signals() < 0 ) return FALSE; goto again1; } return error(errno, "info", "group", group); } } else if ( PL_get_chars(group, &name, CVT_ATOMIC|REP_MB) ) { again2: errno = 0; if ( getgrnam_r(name, &grp, buf, sizeof(buf), &pgrp) != 0 ) { if ( errno == EINTR ) { if ( PL_handle_signals() < 0 ) return FALSE; goto again2; } return error(errno, "info", "group", group); } } else { return PL_type_error("group", group); } if ( !pgrp ) return PL_existence_error("group", group); for(memp=pgrp->gr_mem; *memp; memp++) { if ( !PL_unify_list(tail, head, tail) || !PL_unify_chars(head, PL_ATOM|REP_MB, -1, *memp) ) return FALSE; } if ( !PL_unify_nil(tail) ) return FALSE; return PL_unify_term(info, PL_FUNCTOR_CHARS, "group_info", 4, PL_MBCHARS, pgrp->gr_name, PL_MBCHARS, pgrp->gr_passwd, PL_INT, (int)pgrp->gr_gid, PL_TERM, members ); }
int Pause(double t) { HANDLE h; if ( (h = CreateWaitableTimer(NULL, TRUE, NULL)) ) { LARGE_INTEGER ft; ft.QuadPart = -(LONGLONG)(t * 10000000.0); /* 100 nanosecs per tick */ SetWaitableTimer(h, &ft, 0, NULL, NULL, FALSE); for(;;) { int rc = MsgWaitForMultipleObjects(1, &h, FALSE, INFINITE, QS_ALLINPUT); if ( rc == WAIT_OBJECT_0+1 ) { MSG msg; while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) { TranslateMessage(&msg); DispatchMessage(&msg); } if ( PL_handle_signals() < 0 ) { CloseHandle(h); return FALSE; } } else break; } CloseHandle(h); return TRUE; } else /* Pre NT implementation */ { DWORD msecs = (DWORD)(t * 1000.0); while( msecs >= 100 ) { Sleep(100); if ( PL_handle_signals() < 0 ) return FALSE; msecs -= 100; } if ( msecs > 0 ) Sleep(msecs); return TRUE; } }
int lockout_readers(rwlock *lock) { pthread_mutex_lock(&lock->mutex); if ( lock->readers == 0 ) { ok: lock->allow_readers = FALSE; pthread_mutex_unlock(&lock->mutex); return TRUE; } lock->waiting_upgrade++; for(;;) { int rc = pthread_cond_wait(&lock->upcondvar, &lock->mutex); if ( rc == EINTR ) { if ( PL_handle_signals() < 0 ) { lock->waiting_upgrade--; pthread_mutex_unlock(&lock->mutex); return FALSE; } continue; } else if ( rc == 0 ) { if ( lock->readers == 0 ) { lock->waiting_upgrade--; goto ok; } } else { assert(0); /* TBD: OS errors */ } } }
static int win32_cond_wait(win32_cond_t *cv, CRITICAL_SECTION *external_mutex) { int rc; cv->waiters++; LeaveCriticalSection(external_mutex); rc = MsgWaitForMultipleObjects(1, cv->events, FALSE, /* wait for either event */ INFINITE, QS_ALLINPUT); if ( rc == WAIT_OBJECT_0+1 ) { MSG msg; while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) { TranslateMessage(&msg); DispatchMessage(&msg); } if ( PL_handle_signals() < 0 ) { EnterCriticalSection(external_mutex); return WAIT_INTR; } } EnterCriticalSection(external_mutex); cv->waiters--; return 0; }
static int wait_success(atom_t name, pid_t pid) { pid_t p2; for(;;) { int status; if ( (p2=waitpid(pid, &status, 0)) == pid ) { if ( WIFEXITED(status) && WEXITSTATUS(status) == 0 ) { return TRUE; } else { term_t code, ex; if ( (code = PL_new_term_ref()) && (ex = PL_new_term_ref()) && unify_exit_status(code, status) && PL_unify_term(ex, PL_FUNCTOR, FUNCTOR_error2, PL_FUNCTOR, FUNCTOR_process_error2, PL_ATOM, name, PL_TERM, code, PL_VARIABLE) ) return PL_raise_exception(ex); return FALSE; } } if ( p2 == -1 && errno == EINTR ) { if ( PL_handle_signals() < 0 ) return FALSE; } } }
static int wait_for_pid(pid_t pid, term_t code, wait_options *opts) { pid_t p2; int status; if ( opts->has_timeout && opts->timeout == 0.0 ) { if ( (p2=waitpid(pid, &status, WNOHANG)) == pid ) return unify_exit_status(code, status); else if ( p2 == 0 ) return PL_unify_atom(code, ATOM_timeout); else { term_t PID; error: return ((PID = PL_new_term_ref()) && PL_put_integer(PID, pid) && pl_error(NULL, 0, "waitpid", ERR_ERRNO, errno, "wait", "process", PID)); } } for(;;) { if ( (p2=waitpid(pid, &status, 0)) == pid ) return unify_exit_status(code, status); if ( p2 == -1 && errno == EINTR ) { if ( PL_handle_signals() < 0 ) return FALSE; } else { goto error; } } }
static foreign_t pl_user_info(term_t user, term_t info) { int uid; struct passwd pwd, *pwdp; char buf[1000]; char *name; if ( PL_get_integer(user, &uid) ) { again1: errno = 0; if ( getpwuid_r(uid, &pwd, buf, sizeof(buf), &pwdp) != 0 ) { if ( errno == EINTR ) { if ( PL_handle_signals() < 0 ) return FALSE; goto again1; } return error(errno, "info", "user", user); } } else if ( PL_get_chars(user, &name, CVT_ATOMIC|REP_MB) ) { again2: errno = 0; if ( getpwnam_r(name, &pwd, buf, sizeof(buf), &pwdp) != 0 ) { if ( errno == EINTR ) { if ( PL_handle_signals() < 0 ) return FALSE; goto again2; } return error(errno, "info", "user", user); } } else { return PL_type_error("user", user); } if ( !pwdp ) return PL_existence_error("user", user); return PL_unify_term(info, PL_FUNCTOR_CHARS, "user_info", 7, PL_MBCHARS, pwdp->pw_name, PL_MBCHARS, pwdp->pw_passwd, PL_INT, (int)pwdp->pw_uid, PL_INT, (int)pwdp->pw_gid, PL_MBCHARS, pwdp->pw_gecos, PL_MBCHARS, pwdp->pw_dir, PL_MBCHARS, pwdp->pw_shell ); }
static foreign_t pl_pce_dispatch(void) { pceDispatch(-1, 250); if ( PL_handle_signals() == -1 || PL_exception(0) ) return FALSE; return TRUE; }
int wrlock(rwlock *lock, int allow_readers) { int self = PL_thread_self(); if ( lock->writer == self ) /* recursive write lock, used for */ { lock->lock_level++; /* nested transactions */ return TRUE; } pthread_mutex_lock(&lock->mutex); if ( lock->writer == -1 && lock->readers == 0 ) { ok: lock->writer = self; lock->lock_level = 1; lock->allow_readers = allow_readers; pthread_mutex_unlock(&lock->mutex); DEBUG(3, Sdprintf("WRLOCK(%d): OK\n", self)); return TRUE; } if ( self < lock->thread_max && lock->read_by_thread[self] > 0 ) { DEBUG(1, Sdprintf("SELF(%d) has %d readers\n", self, lock->read_by_thread[self])); pthread_mutex_unlock(&lock->mutex); return permission_error("write", "rdf_db", "default", "Operation would deadlock"); } lock->waiting_writers++; DEBUG(3, Sdprintf("WRLOCK(%d): waiting ...\n", self)); for(;;) { int rc = pthread_cond_wait(&lock->wrcondvar, &lock->mutex); if ( rc == EINTR ) { if ( PL_handle_signals() < 0 ) { lock->waiting_writers--; pthread_mutex_unlock(&lock->mutex); return FALSE; } continue; } else if ( rc == 0 ) { if ( lock->writer == -1 && lock->readers == 0 ) { lock->waiting_writers--; goto ok; } } else { assert(0); /* TBD: OS errors */ } } }
static foreign_t in_pce_thread_sync2(term_t goal, term_t vars) { prolog_goal *g = malloc(sizeof(*g)); MSG msg; int rc = FALSE; if ( !g ) return PL_resource_error("memory"); if ( !init_prolog_goal(g, goal, TRUE) ) { free(g); return FALSE; } g->client = GetCurrentThreadId(); PostMessage(context.window, WM_CALL, (WPARAM)0, (LPARAM)g); while( GetMessage(&msg, NULL, 0, 0) ) { TranslateMessage(&msg); DispatchMessage(&msg); if ( PL_handle_signals() < 0 ) return FALSE; switch(g->state) { case G_TRUE: { term_t v = PL_new_term_ref(); rc = PL_recorded(g->result, v) && PL_unify(vars, v); PL_erase(g->result); goto out; } case G_FALSE: goto out; case G_ERROR: { term_t ex = PL_new_term_ref(); if ( PL_recorded(g->result, ex) ) rc = PL_raise_exception(ex); PL_erase(g->result); goto out; } default: continue; } } out: free(g); return rc; }
static int wait_for_process(process_context *pc) { for(;;) { int status; pid_t p2; if ( (p2=waitpid(pc->pid, &status, 0)) == pc->pid ) { PL_free(pc); return TRUE; } if ( errno == EINTR && PL_handle_signals() >= 0 ) continue; PL_free(pc); return FALSE; } }
int rdlock(rwlock *lock) { int self = PL_thread_self(); if ( lock->writer == self ) { lock->lock_level++; /* read nested in write */ return TRUE; } pthread_mutex_lock(&lock->mutex); if ( lock->allow_readers == TRUE ) { ok: lock->readers++; register_reader(lock, self); pthread_mutex_unlock(&lock->mutex); return TRUE; } lock->waiting_readers++; for(;;) { int rc = pthread_cond_wait(&lock->rdcondvar, &lock->mutex); if ( rc == EINTR ) { if ( PL_handle_signals() < 0 ) { lock->waiting_readers--; pthread_mutex_unlock(&lock->mutex); return FALSE; } continue; } else if ( rc == 0 ) { if ( lock->allow_readers == TRUE ) { lock->waiting_readers--; goto ok; } } else { assert(0); /* TBD: OS errors */ } } }
static int wait_process_handle(HANDLE process, ULONG *rc, DWORD timeout) { DWORD wc; retry: wc = MsgWaitForMultipleObjects(1, &process, FALSE, /* return on any event */ timeout, QS_ALLINPUT); switch(wc) { case WAIT_OBJECT_0: if ( !GetExitCodeProcess(process, rc) ) { win_error("GetExitCodeProcess"); CloseHandle(process); return FALSE; } CloseHandle(process); return TRUE; case WAIT_OBJECT_0+1: { MSG msg; while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) { TranslateMessage(&msg); DispatchMessage(&msg); if ( PL_handle_signals() < 0 ) return FALSE; } goto retry; } case WAIT_TIMEOUT: return WP_TIMEOUT; default: win_error("WaitForSingleObject"); CloseHandle(process); return FALSE; } }
static foreign_t tcp_select(term_t Streams, term_t Available, term_t timeout) { fd_set fds; struct timeval t, *to; double time; int n, max = 0, ret, min = 1000000; fdentry *map = NULL; term_t head = PL_new_term_ref(); term_t streams = PL_copy_term_ref(Streams); term_t available = PL_copy_term_ref(Available); term_t ahead = PL_new_term_ref(); int from_buffer = 0; atom_t a; FD_ZERO(&fds); while( PL_get_list(streams, head, streams) ) { IOSTREAM *s; #ifdef __WINDOWS__ nbio_sock_t fd; #else int fd; #endif fdentry *e; if ( !PL_get_stream_handle(head, &s) ) return FALSE; #ifdef __WINDOWS__ fd = fdFromHandle(s->handle); #else fd = Sfileno(s); #endif PL_release_stream(s); if ( fd < 0 || !is_socket_stream(s) ) { return pl_error("tcp_select", 3, NULL, ERR_DOMAIN, head, "socket_stream"); } /* check for input in buffer */ if ( s->bufp < s->limitp ) { if ( !PL_unify_list(available, ahead, available) || !PL_unify(ahead, head) ) return FALSE; from_buffer++; } e = alloca(sizeof(*e)); e->fd = fd; e->stream = PL_copy_term_ref(head); e->next = map; map = e; #ifdef __WINDOWS__ FD_SET((SOCKET)fd, &fds); #else FD_SET(fd, &fds); #endif if ( fd > max ) max = fd; if( fd < min ) min = fd; } if ( !PL_get_nil(streams) ) return pl_error("tcp_select", 3, NULL, ERR_TYPE, Streams, "list"); if ( from_buffer > 0 ) return PL_unify_nil(available); if ( PL_get_atom(timeout, &a) && a == ATOM_infinite ) { to = NULL; } else { if ( !PL_get_float(timeout, &time) ) return pl_error("tcp_select", 3, NULL, ERR_TYPE, timeout, "number"); if ( time >= 0.0 ) { t.tv_sec = (int)time; t.tv_usec = ((int)(time * 1000000) % 1000000); } else { t.tv_sec = 0; t.tv_usec = 0; } to = &t; } while( (ret=nbio_select(max+1, &fds, NULL, NULL, to)) == -1 && errno == EINTR ) { fdentry *e; if ( PL_handle_signals() < 0 ) return FALSE; /* exception */ FD_ZERO(&fds); /* EINTR may leave fds undefined */ for(e=map; e; e=e->next) /* so we rebuild it to be safe */ { FD_SET((SOCKET)e->fd, &fds); } } switch(ret) { case -1: return pl_error("tcp_select", 3, NULL, ERR_ERRNO, errno, "select", "streams", Streams); case 0: /* Timeout */ break; default: /* Something happened -> check fds */ for(n=min; n <= max; n++) { if ( FD_ISSET(n, &fds) ) { if ( !PL_unify_list(available, ahead, available) || !PL_unify(ahead, findmap(map, n)) ) return FALSE; } } break; } return PL_unify_nil(available); }
/** polling loop til buffer ready */ ssize_t Swipl_IO::_read_(char *buf, size_t bufsize) { qDebug() << "_read_" << CVP(target); int thid = PL_thread_self(); // handle setup interthread and termination for ( ; ; ) { { QMutexLocker lk(&sync); if (target) { if (!target->thids.contains(thid)) { target->add_thread(thid); int rc = PL_thread_at_exit(eng_at_exit, this, FALSE); qDebug() << "installed" << rc; } break; } } if ( PL_handle_signals() < 0 ) return -1; SwiPrologEngine::msleep(10); } if ( buffer.isEmpty() ) { PL_write_prompt(TRUE); emit user_prompt(thid, SwiPrologEngine::is_tty(this)); } for ( ; ; ) { { QMutexLocker lk(&sync); if (!query.isEmpty()) { try { int rc = PlCall(query.toStdWString().data()); qDebug() << "PlCall" << query << rc; } catch(PlException e) { qDebug() << t2w(e); } query.clear(); } uint n = buffer.length(); Q_ASSERT(bufsize >= n); if (n > 0) { uint l = bufsize < n ? bufsize : n; memcpy(buf, buffer, l); buffer.remove(0, l); return l; } if (target->status == ConsoleEdit::eof) { target->status = ConsoleEdit::running; return 0; } } if ( PL_handle_signals() < 0 ) return -1; SwiPrologEngine::msleep(10); } }
static foreign_t in_pce_thread_sync2(term_t goal, term_t vars) { prolog_goal *g; int rc; if ( !setup() ) return FALSE; if ( !(g = malloc(sizeof(*g))) ) return PL_resource_error("memory"); if ( !init_prolog_goal(g, goal, TRUE) ) return FALSE; pthread_cond_init(&g->cv, NULL); pthread_mutex_init(&g->mutex, NULL); rc = write(context.pipe[1], &g, sizeof(g)); if ( rc == sizeof(g) ) { rc = FALSE; pthread_mutex_lock(&g->mutex); for(;;) { struct timespec timeout; #ifdef HAVE_CLOCK_GETTIME struct timespec now; clock_gettime(CLOCK_REALTIME, &now); timeout.tv_sec = now.tv_sec; timeout.tv_nsec = (now.tv_nsec+250000000); #else struct timeval now; gettimeofday(&now, NULL); timeout.tv_sec = now.tv_sec; timeout.tv_nsec = (now.tv_usec+250000) * 1000; #endif if ( timeout.tv_nsec >= 1000000000 ) /* some platforms demand this */ { timeout.tv_nsec -= 1000000000; timeout.tv_sec += 1; } pthread_cond_timedwait(&g->cv, &g->mutex, &timeout); if ( PL_handle_signals() < 0 ) goto out; switch(g->state) { case G_TRUE: { term_t v = PL_new_term_ref(); rc = PL_recorded(g->result, v) && PL_unify(vars, v); PL_erase(g->result); goto out; } case G_FALSE: goto out; case G_ERROR: { term_t ex = PL_new_term_ref(); if ( PL_recorded(g->result, ex) ) rc = PL_raise_exception(ex); PL_erase(g->result); goto out; } default: continue; } } out: pthread_mutex_unlock(&g->mutex); } pthread_mutex_destroy(&g->mutex); pthread_cond_destroy(&g->cv); free(g); return rc; }