| /* process.h |
| |
| Written by Robert Collins <rbtcollins@hotmail.com> |
| |
| This file is part of Cygwin. |
| |
| This software is a copyrighted work licensed under the terms of the |
| Cygwin license. Please consult the file "CYGWIN_LICENSE" for |
| details. */ |
| |
| #ifndef _PROCESS_H |
| #define _PROCESS_H |
| |
| #include <assert.h> |
| |
| #include "threaded_queue.h" |
| |
| class process_cleanup : public queue_request |
| { |
| public: |
| process_cleanup (class process *const theprocess) |
| : _process (theprocess) |
| { |
| assert (_process); |
| } |
| |
| virtual ~process_cleanup (); |
| |
| virtual void process (); |
| |
| private: |
| class process *const _process; |
| }; |
| |
| class process; |
| |
| class cleanup_routine |
| { |
| friend class process; |
| |
| public: |
| cleanup_routine (void *const key) |
| : _key (key), |
| _next (NULL) |
| {} |
| |
| virtual ~cleanup_routine () = 0; |
| |
| bool operator== (const cleanup_routine &rhs) const |
| { |
| return _key == rhs._key; |
| } |
| |
| void *key () const { return _key; } |
| |
| /* MUST BE SYNCHRONOUS */ |
| virtual void cleanup (class process *) = 0; |
| |
| private: |
| void *const _key; |
| cleanup_routine *_next; |
| }; |
| |
| class process_cache; |
| |
| #define hold() _hold(__FILE__,__LINE__) |
| #define release() _release(__FILE__,__LINE__) |
| |
| class process |
| { |
| friend class process_cache; |
| friend class process_cleanup; |
| |
| public: |
| process (pid_t cygpid, DWORD winpid); |
| ~process (); |
| |
| pid_t cygpid () const { return _cygpid; } |
| DWORD winpid () const { return _winpid; } |
| HANDLE handle () const { return _hProcess; } |
| |
| bool is_active () const { return _exit_status == STILL_ACTIVE; } |
| |
| void _hold (const char *file, int line) { |
| _debug (file, line, "Try hold(%lu)", _cygpid); |
| EnterCriticalSection (&_access); |
| _debug (file, line, "holding (%lu)", _cygpid); |
| } |
| void _release (const char *file, int line) { |
| _debug (file, line, "leaving (%lu)", _cygpid); |
| LeaveCriticalSection (&_access); |
| } |
| |
| bool add (cleanup_routine *); |
| bool remove (const cleanup_routine *); |
| |
| private: |
| const pid_t _cygpid; |
| const DWORD _winpid; |
| HANDLE _hProcess; |
| LONG _cleaning_up; |
| DWORD _exit_status; // Set in the constructor and in exit_code (). |
| cleanup_routine *_routines_head; |
| /* used to prevent races-on-delete */ |
| CRITICAL_SECTION _access; |
| class process *_next; |
| |
| DWORD check_exit_code (); |
| void cleanup (); |
| }; |
| |
| class process_cache |
| { |
| // Number of special (i.e., non-process) handles in _wait_array. |
| // See wait_for_processes () and sync_wait_array () for details. |
| enum { |
| SPECIALS_COUNT = 2 |
| }; |
| |
| class submission_loop : public queue_submission_loop |
| { |
| public: |
| submission_loop (process_cache *const cache, threaded_queue *const queue) |
| : queue_submission_loop (queue, true), |
| _cache (cache) |
| { |
| assert (_cache); |
| } |
| |
| private: |
| process_cache *const _cache; |
| |
| virtual void request_loop (); |
| }; |
| |
| friend class submission_loop; |
| |
| public: |
| process_cache (const size_t max_procs, const unsigned int initial_workers); |
| ~process_cache (); |
| |
| class process *process (pid_t cygpid, DWORD winpid); |
| |
| bool running () const { return _queue.running (); } |
| |
| bool start () { return _queue.start (); } |
| bool stop () { return _queue.stop (); } |
| |
| private: |
| threaded_queue _queue; |
| submission_loop _submitter; |
| |
| size_t _processes_count; |
| size_t _max_process_count; |
| class process *_processes_head; // A list sorted by winpid. |
| |
| // Access to the _wait_array and related fields is not thread-safe, |
| // since they are used solely by wait_for_processes () and its callees. |
| |
| HANDLE _wait_array[5 * MAXIMUM_WAIT_OBJECTS]; |
| class process *_process_array[5 * MAXIMUM_WAIT_OBJECTS]; |
| |
| HANDLE _cache_add_trigger; // Actually both add and remove. |
| CRITICAL_SECTION _cache_write_access; // Actually both read and write access. |
| |
| void wait_for_processes (HANDLE interrupt); |
| size_t sync_wait_array (HANDLE interrupt); |
| void check_and_remove_process (const size_t index); |
| |
| class process *find (DWORD winpid, class process **previous = NULL); |
| }; |
| |
| #endif /* _PROCESS_H */ |