note
	description: "Class defining an Eiffel thread."
	legal: "See notice at end of class."
	status: "See notice at end of class."
	date: "$Date: 2018-01-22 11:15:04 +0000 (Mon, 22 Jan 2018) $"
	revision: "$Revision: 101252 $"

deferred class 
	THREAD

inherit
	THREAD_CONTROL

feature {NONE} -- Initialization

	make
			-- Initialize Current.
		do
			create launch_mutex.make
		end
	
feature -- Access

	thread_id: POINTER
			-- Thread-id of the current thread object.

	terminated: BOOLEAN
			-- True if the thread has terminated.
	
feature -- Basic operations

	execute
			-- Routine executed when thread is launched.
		deferred
		end

	frozen launch
			-- Initialize a new thread running execute.
			-- Set is_last_launch_successful to True if successful, False otherwise.			
		require
			thread_capable: {PLATFORM}.is_thread_capable
			is_launchable: is_launchable
		do
			launch_with_attributes (create {THREAD_ATTRIBUTES}.make)
		end

	frozen launch_with_attributes (attr: THREAD_ATTRIBUTES)
			-- Initialize a new thread running execute, using attributes.
			-- Set is_last_launch_successful to True if successful, False otherwise.
		require
			thread_capable: {PLATFORM}.is_thread_capable
			is_launchable: is_launchable
		do
			launch_mutex.lock
			if not is_launchable then
				Is_last_launch_successful_cell.put (False)
			else
				create_thread_with_attr (Current, $thr_main, $thr_set_terminated, attr.item)
				thread_id := last_created_thread;
				Is_last_launch_successful_cell.put (True)
			end;
			launch_mutex.unlock
		rescue
			Is_last_launch_successful_cell.put (False);
			launch_mutex.unlock
		end

	exit
			-- Exit calling thread. Must be called from the thread itself.
		require
			is_exit_supported: is_exit_supported
			self: current_thread_id = thread_id
		do
			c_exit
		end

	sleep (nanoseconds: INTEGER_64)
			-- Suspend thread execution for interval specified in
			-- nanoseconds (1 nanosecond = 10^(-9) second).
		require
			self: current_thread_id = thread_id
			non_negative_nanoseconds: nanoseconds >= 0
		do
			(create {EXECUTION_ENVIRONMENT}).sleep (nanoseconds)
		end
	
feature {NONE} -- Basic operations

	c_exit
			-- Implementation of exit.
		require
			is_exit_supported: is_exit_supported
			self: 
		external
			"C use %"eif_threads.h%""
		alias
			"eif_thr_exit"
		end
	
feature -- Status report

	is_exit_supported: BOOLEAN
			-- Can exit be called?
		do
			Result := True
		ensure
			is_class: class
		end

	is_launchable: BOOLEAN
			-- Can we launch a new thread?
		do
			Result := launch_mutex.is_set and thread_id = default_pointer and not terminated
		end

	is_last_launch_successful: BOOLEAN
			-- Was the last call to launch or launch_with_attributes in current thread
			-- of execution successful?
		do
			Result := Is_last_launch_successful_cell.item
		end
	
feature -- Synchronization

	join
			-- The calling thread waits for the current child thread to terminate.
		do
			if not terminated then
				thread_wait (Current, $thr_get_terminated)
			end
		end

	join_with_timeout (a_timeout_ms: NATURAL_64): BOOLEAN
			-- The calling thread waits for the current child thread to
			-- terminate for at most a_timeout_ms milliseconds.
			-- True if wait terminates within a_timeout_ms, False otherwise.
		do
			if terminated then
				Result := True
			else
				Result := thread_wait_with_timeout (Current, $thr_get_terminated, a_timeout_ms)
			end
		end
	
feature {NONE} -- Implementation

	frozen thr_main (a_logical_id: INTEGER_32)
			-- Call thread routine.
		do
			launch_mutex.lock;
			launch_mutex.unlock
			execute;
			launch_mutex.lock
			terminated := True
			thread_id := default_pointer;
			launch_mutex.unlock
		rescue
			launch_mutex.lock
			terminated := True
			thread_id := default_pointer;
			launch_mutex.unlock
		end

	frozen thr_get_terminated: BOOLEAN
			-- Get value of terminated.
		do
			launch_mutex.lock
			Result := terminated;
			launch_mutex.unlock
		end

	frozen thr_set_terminated (b: BOOLEAN)
			-- Set terminated to b.
		do
			launch_mutex.lock
			terminated := b;
			launch_mutex.unlock
		end

	launch_mutex: MUTEX
			-- Mutex used to ensure that no two threads call launch or launch_with_attributes
			-- on the same object. This ensures the validity of querying thread_id from
			-- the launch routines.

	Is_last_launch_successful_cell: CELL [BOOLEAN]
			-- Internal storage for is_last_launch_successful.
			-- It is a once per thread and not an attribute because if you have multiple threads
			-- calling launch on the same object, one will set it to True, and the other will
			-- override the value with False.
		once
			create Result.put (False)
		end
	
feature {NONE} -- Externals

	create_thread_with_attr (current_obj: THREAD; init_func, set_terminated_func, attr: POINTER)
			-- Initialize and start thread, after setting its priority
			-- and stack size.
		external
			"C signature (EIF_OBJECT, EIF_PROCEDURE, EIF_PROCEDURE, EIF_POINTER) use %"eif_threads.h%""
		alias
			"eif_thr_create_with_attr"
		end

	thread_wait (current_obj: THREAD; get_terminated_func: POINTER)
			-- The calling C thread waits for the current Eiffel thread to
			-- terminate.
		external
			"C signature (EIF_OBJECT, EIF_BOOLEAN_FUNCTION) use %"eif_threads.h%""
		alias
			"eif_thr_wait"
		end

	thread_wait_with_timeout (current_obj: THREAD; get_terminated_func: POINTER; a_timeout_ms: NATURAL_64): BOOLEAN
			-- The calling C thread waits for the current Eiffel thread to
			-- terminate.
		external
			"C signature (EIF_OBJECT, EIF_BOOLEAN_FUNCTION, EIF_NATURAL_64): EIF_BOOLEAN use %"eif_threads.h%""
		alias
			"eif_thr_wait_with_timeout"
		end

	last_created_thread: POINTER
			-- Returns a pointer to the thread-id of the last created thread.
		external
			"C use %"eif_threads.h%""
		alias
			"eif_thr_last_thread"
		end
	
note
	copyright: "Copyright (c) 1984-2018, Eiffel Software and others"
	license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
	source: "[
		Eiffel Software
		5949 Hollister Ave., Goleta, CA 93117 USA
		Telephone 805-685-1006, Fax 805-685-6869
		Website http://www.eiffel.com
		Customer support http://support.eiffel.com
	]"

end -- class THREAD

Generated by ISE EiffelStudio