def semlock_acquire(self, space, block, w_timeout): if not block: full_msecs = 0 elif space.is_none(w_timeout): full_msecs = rwin32.INFINITE else: timeout = space.float_w(w_timeout) timeout *= 1000.0 if timeout < 0.0: timeout = 0.0 elif timeout >= 0.5 * rwin32.INFINITE: # 25 days raise oefmt(space.w_OverflowError, "timeout is too large") full_msecs = r_uint(int(timeout + 0.5)) # check whether we can acquire without blocking res = rwin32.WaitForSingleObject(self.handle, 0) if res != rwin32.WAIT_TIMEOUT: self.last_tid = rthread.get_ident() self.count += 1 return True msecs = full_msecs start = _GetTickCount() while True: from pypy.module.time.interp_time import State interrupt_event = space.fromcache(State).get_interrupt_event() handles = [self.handle, interrupt_event] # do the wait rwin32.ResetEvent(interrupt_event) res = rwin32.WaitForMultipleObjects(handles, timeout=msecs) if res != rwin32.WAIT_OBJECT_0 + 1: break # got SIGINT so give signal handler a chance to run time.sleep(0.001) # if this is main thread let KeyboardInterrupt be raised _check_signals(space) # recalculate timeout if msecs != rwin32.INFINITE: ticks = _GetTickCount() if r_uint(ticks - start) >= full_msecs: return False msecs = full_msecs - r_uint(ticks - start) # handle result if res != rwin32.WAIT_TIMEOUT: self.last_tid = rthread.get_ident() self.count += 1 return True return False
def f(num): rthread.get_ident() # register TLOFS_thread_ident code = MyCode("py:x:foo:3") rvmprof.register_code(code, get_name) fd = os.open(tmpfilename, os.O_WRONLY | os.O_CREAT, 0666) period = 0.0001 rvmprof.enable(fd, period) res = main(code, num) #assert res == 499999500000 rvmprof.disable() os.close(fd) return 0
def acquire_w(self, space, blocking=True, timeout=-1.0): """Lock the lock. `blocking` indicates whether we should wait for the lock to be available or not. If `blocking` is False and another thread holds the lock, the method will return False immediately. If `blocking` is True and another thread holds the lock, the method will wait for the lock to be released, take it and then return True. (note: the blocking operation is not interruptible.) In all other cases, the method will return True immediately. Precisely, if the current thread already holds the lock, its internal counter is simply incremented. If nobody holds the lock, the lock is taken and its internal counter initialized to 1.""" microseconds = parse_acquire_args(space, blocking, timeout) tid = rthread.get_ident() if self.rlock_count > 0 and tid == self.rlock_owner: try: self.rlock_count = ovfcheck(self.rlock_count + 1) except OverflowError: raise oefmt(space.w_OverflowError, "internal lock count overflowed") return space.w_True r = True if self.rlock_count > 0 or not self.lock.acquire(False): if not blocking: return space.w_False r = acquire_timed(space, self.lock, microseconds) r = (r == RPY_LOCK_ACQUIRED) if r: assert self.rlock_count == 0 self.rlock_owner = tid self.rlock_count = 1 return space.newbool(r)
def acquire_w(self, space, blocking=1): """Acquire a lock, blocking or non-blocking. When invoked without arguments: if this thread already owns the lock, increment the recursion level by one, and return immediately. Otherwise, if another thread owns the lock, block until the lock is unlocked. Once the lock is unlocked (not owned by any thread), then grab ownership, set the recursion level to one, and return. If more than one thread is blocked waiting until the lock is unlocked, only one at a time will be able to grab ownership of the lock. There is no return value in this case. When invoked with the blocking argument set to true, do the same thing as when called without arguments, and return true. When invoked with the blocking argument set to false, do not block. If a call without an argument would block, return false immediately; otherwise, do the same thing as when called without arguments, and return true. """ tid = rthread.get_ident() if tid == self.rlock_owner: try: self.rlock_count = ovfcheck(self.rlock_count + 1) except OverflowError: raise oefmt(space.w_OverflowError, "internal lock count overflowed") return space.w_True rc = self.lock.acquire(blocking != 0) if rc: self.rlock_owner = tid self.rlock_count = 1 return space.newbool(rc)
def f(): state.data = [] state.datalen1 = 0 state.datalen2 = 0 state.datalen3 = 0 state.datalen4 = 0 state.threadlocals = my_gil_threadlocals state.threadlocals.setup_threads(space) subident = thread.start_new_thread(bootstrap, ()) mainident = thread.get_ident() runme(True) still_waiting = 3000 while len(state.data) < 2 * N: debug_print(len(state.data)) if not still_waiting: raise ValueError("time out") still_waiting -= 1 if not we_are_translated(): gil.before_external_call() time.sleep(0.01) if not we_are_translated(): gil.after_external_call() debug_print("leaving!") i1 = i2 = 0 for tid, i in state.data: if tid == mainident: assert i == i1 i1 += 1 elif tid == subident: assert i == i2 i2 += 1 else: assert 0 assert i1 == N + skew assert i2 == N - skew return len(state.data)
def f(): state.data = [] state.datalen1 = 0 state.datalen2 = 0 state.datalen3 = 0 state.datalen4 = 0 state.threadlocals = my_gil_threadlocals state.threadlocals.setup_threads(space) subident = thread.start_new_thread(bootstrap, ()) mainident = thread.get_ident() runme(True) still_waiting = 3000 while len(state.data) < 2*N: debug_print(len(state.data)) if not still_waiting: llop.debug_print(lltype.Void, "timeout. progress: " "%d of 2*N (= %f%%)" % \ (len(state.data), 2*N, 100*len(state.data)/(2.0*N))) raise ValueError("time out") still_waiting -= 1 if not we_are_translated(): rgil.release() time.sleep(0.1) if not we_are_translated(): rgil.acquire() debug_print("leaving!") i1 = i2 = 0 for tid, i in state.data: if tid == mainident: assert i == i1; i1 += 1 elif tid == subident: assert i == i2; i2 += 1 else: assert 0 assert i1 == N + skew assert i2 == N - skew return len(state.data)
def f(): state.data = [] state.datalen1 = 0 state.datalen2 = 0 state.datalen3 = 0 state.datalen4 = 0 state.threadlocals = gil.GILThreadLocals() state.threadlocals.setup_threads(space) thread.gc_thread_prepare() subident = thread.start_new_thread(bootstrap, ()) mainident = thread.get_ident() runme(True) still_waiting = 3000 while len(state.data) < 2*N: debug_print(len(state.data)) if not still_waiting: raise ValueError("time out") still_waiting -= 1 if not we_are_translated(): gil.before_external_call() time.sleep(0.01) if not we_are_translated(): gil.after_external_call() debug_print("leaving!") i1 = i2 = 0 for tid, i in state.data: if tid == mainident: assert i == i1; i1 += 1 elif tid == subident: assert i == i2; i2 += 1 else: assert 0 assert i1 == N + skew assert i2 == N - skew return len(state.data)
def is_owned_w(self, space): """For internal use by `threading.Condition`.""" tid = rthread.get_ident() if self.rlock_count > 0 and self.rlock_owner == tid: return space.w_True else: return space.w_False
def _set_ec(self, ec, register_in_valuedict=True): ident = rthread.get_ident() if self._mainthreadident == 0 or self._mainthreadident == ident: ec._signals_enabled = 1 # the main thread is enabled self._mainthreadident = ident if register_in_valuedict: self._valuedict[ident] = ec self.raw_thread_local.set(ec)
def run(space, w_callable, args): try: space.call_args(w_callable, args) except OperationError, e: if not e.match(space, space.w_SystemExit): ident = rthread.get_ident() where = 'thread %d started by ' % ident e.write_unraisable(space, where, w_callable, with_traceback=True) e.clear(space)
def main(argv=[]): rthread.get_ident() # force TLOFS_thread_ident if NonConstant(False): # Hack to give os.open() the correct annotation os.open('foo', 1, 1) code1 = MyCode(6500) fd = os.open(PROF_FILE, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0666) rvmprof.enable(fd, 0.01) # code2 = MyCode(9100) stop = time.time() + 1 while time.time() < stop: interpret(code1) interpret(code2) # rvmprof.disable() os.close(fd) return 0
def _set_ec(self, ec): ident = rthread.get_ident() if self._mainthreadident == 0 or self._mainthreadident == ident: ec._signals_enabled = 1 # the main thread is enabled self._mainthreadident = ident self._valuedict[ident] = ec # This logic relies on hacks and _make_sure_does_not_move(). # It only works because we keep the 'ec' alive in '_valuedict' too. self.raw_thread_local.set(ec)
def reinit_threads(self, space): "Called in the child process after a fork()" ident = rthread.get_ident() ec = self.getvalue() if ident != self._mainthreadident: ec._signals_enabled += 1 self._cleanup_() self._mainthreadident = ident self.setvalue(ec)
def get_ident(space): """Return a non-zero integer that uniquely identifies the current thread amongst other threads that exist simultaneously. This may be used to identify per-thread resources. Even though on some platforms threads identities may appear to be allocated consecutive numbers starting at 1, this behavior should not be relied upon, and the number should be seen purely as a magic cookie. A thread's identity may be reused for another thread after it exits.""" ident = rthread.get_ident() return space.newint(ident)
def get_ident(space): """Return a non-zero integer that uniquely identifies the current thread amongst other threads that exist simultaneously. This may be used to identify per-thread resources. Even though on some platforms threads identities may appear to be allocated consecutive numbers starting at 1, this behavior should not be relied upon, and the number should be seen purely as a magic cookie. A thread's identity may be reused for another thread after it exits.""" ident = rthread.get_ident() return space.wrap(ident)
def getvalue(self): ident = rthread.get_ident() if ident == self._mostrecentkey: result = self._mostrecentvalue else: value = self._valuedict.get(ident, None) # slow path: update the minicache self._mostrecentkey = ident self._mostrecentvalue = value result = value return result
def run(space, w_callable, args): # add the ExecutionContext to space.threadlocals space.threadlocals.enter_thread(space) try: space.call_args(w_callable, args) except OperationError, e: if not e.match(space, space.w_SystemExit): ident = rthread.get_ident() where = 'thread %d started by ' % ident e.write_unraisable(space, where, w_callable, with_traceback=True) e.clear(space)
def __exit__(self, *args): assert self.rec_level > 0 self.rec_level -= 1 if self.space.config.objspace.usemodules.thread: from rpython.rlib import rthread # tid = rthread.get_ident() assert tid == self.lock_owner if self.rec_level == 0: self.lock_owner = 0 self.lock.release()
def sleep(space, secs): _check_sleep_arg(space, secs) # as decreed by Guido, only the main thread can be # interrupted. main_thread = space.fromcache(State).main_thread interruptible = (main_thread == thread.get_ident()) MAX = sys.maxint / 1000.0 # > 24 days while secs > MAX: _simple_sleep(space, MAX, interruptible) secs -= MAX _simple_sleep(space, secs, interruptible)
def reinit_threads(self, space): "Called in the child process after a fork()" ident = rthread.get_ident() ec = self.get_ec() assert ec is not None old_sig = ec._signals_enabled if ident != self._mainthreadident: old_sig += 1 self._cleanup_() self._mainthreadident = ident self._set_ec(ec) ec._signals_enabled = old_sig
def sleep(space, secs): if secs < 0: raise OperationError(space.w_IOError, space.wrap("Invalid argument: negative time in sleep")) # as decreed by Guido, only the main thread can be # interrupted. main_thread = space.fromcache(State).main_thread interruptible = (main_thread == thread.get_ident()) MAX = sys.maxint / 1000.0 # > 24 days while secs > MAX: _simple_sleep(space, MAX, interruptible) secs -= MAX _simple_sleep(space, secs, interruptible)
def leave_thread(self, space): "Notification that the current thread is about to stop." from pypy.module.thread.os_local import thread_is_stopping ec = self.get_ec() if ec is not None: try: thread_is_stopping(ec) finally: self.raw_thread_local.set(None) ident = rthread.get_ident() try: del self._valuedict[ident] except KeyError: pass
def __enter__(self): # This is a simple recursive lock implementation if self.space.config.objspace.usemodules.thread: from rpython.rlib import rthread # tid = rthread.get_ident() if tid != self.lock_owner: if self.lock is None: self.lock = self.space.allocate_lock() self.lock.acquire(True) assert self.lock_owner == 0 assert self.rec_level == 0 self.lock_owner = tid self.rec_level += 1
def run(space, w_callable, args): # add the ExecutionContext to space.threadlocals space.threadlocals.enter_thread(space) try: space.call_args(w_callable, args) except OperationError as e: if not e.match(space, space.w_SystemExit): ident = rthread.get_ident() where = "thread %d started by " % ident e.write_unraisable(space, where, w_callable, with_traceback=True) e.clear(space) # clean up space.threadlocals to remove the ExecutionContext # entry corresponding to the current thread space.threadlocals.leave_thread(space)
def setvalue(self, value): ident = rthread.get_ident() if value is not None: if self._mainthreadident == 0: value._signals_enabled = 1 # the main thread is enabled self._mainthreadident = ident self._valuedict[ident] = value else: try: del self._valuedict[ident] except KeyError: pass # update the minicache to prevent it from containing an outdated value self._mostrecentkey = ident self._mostrecentvalue = value
def runme(main=False): j = 0 for i in range(N + [-skew, skew][main]): state.datalen1 += 1 # try to crash if the GIL is not state.datalen2 += 1 # correctly acquired state.data.append((thread.get_ident(), i)) state.datalen3 += 1 state.datalen4 += 1 assert state.datalen1 == len(state.data) assert state.datalen2 == len(state.data) assert state.datalen3 == len(state.data) assert state.datalen4 == len(state.data) debug_print(main, i, state.datalen4) rgil.yield_thread() assert i == j j += 1
def runme(main=False): j = 0 for i in range(N + [-skew, skew][main]): state.datalen1 += 1 # try to crash if the GIL is not state.datalen2 += 1 # correctly acquired state.data.append((thread.get_ident(), i)) state.datalen3 += 1 state.datalen4 += 1 assert state.datalen1 == len(state.data) assert state.datalen2 == len(state.data) assert state.datalen3 == len(state.data) assert state.datalen4 == len(state.data) debug_print(main, i, state.datalen4) gil.do_yield_thread() assert i == j j += 1
def acquire(self, space, block=True, w_timeout=None): # check whether we already own the lock if self.kind == RECURSIVE_MUTEX and self._ismine(): self.count += 1 return space.w_True try: got = semlock_acquire(self, space, block, w_timeout) except OSError as e: raise wrap_oserror(space, e) if got: self.last_tid = rthread.get_ident() self.count += 1 return space.w_True else: return space.w_False
def release_w(self, space): """Release the lock, allowing another thread that is blocked waiting for the lock to acquire the lock. The lock must be in the locked state, and must be locked by the same thread that unlocks it; otherwise a `RuntimeError` is raised. Do note that if the lock was acquire()d several times in a row by the current thread, release() needs to be called as many times for the lock to be available for other threads.""" tid = rthread.get_ident() if self.rlock_count == 0 or self.rlock_owner != tid: raise oefmt(space.w_RuntimeError, "cannot release un-acquired lock") self.rlock_count -= 1 if self.rlock_count == 0: self.rlock_owner = 0 self.lock.release()
def run(space, w_callable, args): # add the ExecutionContext to space.threadlocals space.threadlocals.enter_thread(space) try: space.call_args(w_callable, args) except OperationError as e: if not e.match(space, space.w_SystemExit): ident = rthread.get_ident() where = 'thread %d started by ' % ident e.write_unraisable(space, where, w_callable, with_traceback=True) e.clear(space) # clean up space.threadlocals to remove the ExecutionContext # entry corresponding to the current thread space.threadlocals.leave_thread(space)
def semlock_acquire(self, space, block, w_timeout): if not block: deadline = lltype.nullptr(TIMESPECP.TO) elif space.is_none(w_timeout): deadline = lltype.nullptr(TIMESPECP.TO) else: timeout = space.float_w(w_timeout) sec = int(timeout) nsec = int(1e9 * (timeout - sec) + 0.5) now_sec, now_usec = gettimeofday() deadline = lltype.malloc(TIMESPECP.TO, 1, flavor='raw') rffi.setintfield(deadline[0], 'c_tv_sec', now_sec + sec) rffi.setintfield(deadline[0], 'c_tv_nsec', now_usec * 1000 + nsec) val = (rffi.getintfield(deadline[0], 'c_tv_sec') + rffi.getintfield(deadline[0], 'c_tv_nsec') / 1000000000) rffi.setintfield(deadline[0], 'c_tv_sec', val) val = rffi.getintfield(deadline[0], 'c_tv_nsec') % 1000000000 rffi.setintfield(deadline[0], 'c_tv_nsec', val) try: while True: try: if not block: sem_trywait(self.handle) elif not deadline: sem_wait(self.handle) else: sem_timedwait(self.handle, deadline) except OSError as e: if e.errno == errno.EINTR: # again _check_signals(space) continue elif e.errno in (errno.EAGAIN, errno.ETIMEDOUT): return False raise _check_signals(space) self.last_tid = rthread.get_ident() self.count += 1 return True finally: if deadline: lltype.free(deadline, flavor='raw')
def release_w(self, space): """Release a lock, decrementing the recursion level. If after the decrement it is zero, reset the lock to unlocked (not owned by any thread), and if any other threads are blocked waiting for the lock to become unlocked, allow exactly one of them to proceed. If after the decrement the recursion level is still nonzero, the lock remains locked and owned by the calling thread. Only call this method when the calling thread owns the lock. A RuntimeError is raised if this method is called when the lock is unlocked. There is no return value. """ if self.rlock_owner != rthread.get_ident(): raise oefmt(space.w_RuntimeError, "cannot release un-acquired lock") self.rlock_count -= 1 if self.rlock_count == 0: self.rlock_owner = 0 try_release(space, self.lock)
def sleep(space, w_secs): ns = timestamp_w(space, w_secs) if not (ns >= 0): raise oefmt(space.w_ValueError, "sleep length must be non-negative") end_time = _monotonic(space) + float(ns) / SECS_TO_NS while True: if _WIN: # as decreed by Guido, only the main thread can be # interrupted. main_thread = space.fromcache(State).main_thread interruptible = (main_thread == thread.get_ident()) millisecs = ns // MS_TO_NS if millisecs == 0 or not interruptible: rtime.sleep(float(ns) / SECS_TO_NS) break interrupt_event = space.fromcache(State).get_interrupt_event() rwin32.ResetEvent(interrupt_event) rc = rwin32.WaitForSingleObject(interrupt_event, millisecs) if rc != rwin32.WAIT_OBJECT_0: break else: void = lltype.nullptr(rffi.VOIDP.TO) with lltype.scoped_alloc(TIMEVAL) as t: seconds = ns // SECS_TO_NS us = (ns % SECS_TO_NS) // US_TO_NS rffi.setintfield(t, 'c_tv_sec', int(seconds)) rffi.setintfield(t, 'c_tv_usec', int(us)) res = rffi.cast(rffi.LONG, c_select(0, void, void, void, t)) if res == 0: break # normal path if rposix.get_saved_errno() != EINTR: raise exception_from_saved_errno(space, space.w_OSError) space.getexecutioncontext().checksignals() secs = end_time - _monotonic(space) # retry if secs <= 0: break
def startup(self, space): self.main_thread = thread.get_ident() globalState.startup(space)
def __enter__(self): if not self.lock.acquire(False): if self.owner == rthread.get_ident(): raise self.operr self.lock.acquire(True) self.owner = rthread.get_ident()
def __init__(self, ec): # this makes a loop between 'self' and 'ec'. It should not prevent # the __del__ method here from being called. self.ec = ec ec._threadlocals_auto_free = self self.ident = rthread.get_ident()
def try_enter_thread(self, space): if rthread.get_ident() in self._valuedict: return False self.enter_thread(space) return True
def get_possibly_deleted_ec(): ec1 = space.threadlocals.raw_thread_local.get() ec2 = space.threadlocals._valuedict.get(rthread.get_ident(), None) if ec1 is None and ec2 is not None: space.threadlocals.raw_thread_local.set(ec2) return space.threadlocals.__class__.get_ec(space.threadlocals)
def _ismine(self): return self.count > 0 and rthread.get_ident() == self.last_tid
def get_aid(): """Return the thread identifier, cast to an (opaque) address.""" return llmemory.cast_int_to_adr(rthread.get_ident())
def get_ec(self): ec = self.raw_thread_local.get() if not we_are_translated(): assert ec is self._valuedict.get(rthread.get_ident(), None) return ec
def _get_ident(self): from rpython.rlib import rthread tid = rthread.get_ident() assert tid != 0 return tid
return space.wrap(val) @unwrap_spec(block=bool) def acquire(self, space, block=True, w_timeout=None): # check whether we already own the lock if self.kind == RECURSIVE_MUTEX and self._ismine(): self.count += 1 return space.w_True try: got = semlock_acquire(self, space, block, w_timeout) except OSError, e: raise wrap_oserror(space, e) if got: self.last_tid = rthread.get_ident() self.count += 1 return space.w_True else: return space.w_False def release(self, space): if self.kind == RECURSIVE_MUTEX: if not self._ismine(): raise OperationError( space.w_AssertionError, space.wrap("attempt to release recursive lock" " not owned by thread")) if self.count > 1: self.count -= 1 return