Moved httpd library from ewsgi/connectors/standalone/lib/httpd to httpd.
Reused the http_network library as well inside httpd library.
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
note
|
||||
description: "[
|
||||
Implementation of HTTPD_CONNECTION_HANDLER_I for concurrency mode: none
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HTTPD_CONNECTION_HANDLER
|
||||
|
||||
inherit
|
||||
HTTPD_CONNECTION_HANDLER_I
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
initialize
|
||||
do
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
is_shutdown_requested: BOOLEAN
|
||||
-- <Precursor>
|
||||
|
||||
shutdown_requested (a_server: like server): BOOLEAN
|
||||
do
|
||||
-- FIXME: we should probably remove this possibility, check with EWF if this is needed.
|
||||
Result := a_server.controller.shutdown_requested
|
||||
end
|
||||
|
||||
feature {HTTPD_SERVER_I} -- Execution
|
||||
|
||||
accept_incoming_connection (a_listening_socket: HTTPD_STREAM_SOCKET)
|
||||
local
|
||||
cl: HTTPD_STREAM_SOCKET
|
||||
do
|
||||
is_shutdown_requested := is_shutdown_requested or shutdown_requested (server)
|
||||
if is_shutdown_requested then
|
||||
-- Cancel
|
||||
elseif attached factory.new_handler as h then
|
||||
cl := h.client_socket
|
||||
a_listening_socket.accept_to (cl)
|
||||
if h.is_connected then
|
||||
h.safe_execute
|
||||
end
|
||||
else
|
||||
check is_not_full: False end
|
||||
end
|
||||
update_is_shutdown_requested
|
||||
end
|
||||
|
||||
update_is_shutdown_requested
|
||||
do
|
||||
is_shutdown_requested := shutdown_requested (server)
|
||||
end
|
||||
|
||||
shutdown
|
||||
do
|
||||
if not is_shutdown_requested then
|
||||
is_shutdown_requested := True
|
||||
server.controller.shutdown
|
||||
end
|
||||
end
|
||||
|
||||
feature {HTTPD_SERVER_I} -- Status report
|
||||
|
||||
wait_for_completion
|
||||
-- Wait until Current is ready for shutdown
|
||||
do
|
||||
-- no concurrency, then current task should be done.
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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
|
||||
@@ -0,0 +1,32 @@
|
||||
note
|
||||
description : "Concurrent specific feature to implement HTTPD_REQUEST_HANDLER"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_REQUEST_HANDLER
|
||||
|
||||
inherit
|
||||
HTTPD_REQUEST_HANDLER_I
|
||||
redefine
|
||||
is_persistent_connection_supported
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_persistent_connection_supported: BOOLEAN = False
|
||||
-- <Precursor>
|
||||
-- When there is no concurrency support, do not try to support
|
||||
-- persistent connection!
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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
|
||||
@@ -0,0 +1,15 @@
|
||||
note
|
||||
description: "Implementation of request handler factory for concurrency mode: none"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_REQUEST_HANDLER_FACTORY
|
||||
|
||||
inherit
|
||||
HTTPD_REQUEST_HANDLER_FACTORY_I
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
@@ -0,0 +1,146 @@
|
||||
note
|
||||
description: "[
|
||||
Implementation of HTTPD_CONNECTION_HANDLER_I for concurrency mode: SCOOP
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HTTPD_CONNECTION_HANDLER
|
||||
|
||||
inherit
|
||||
HTTPD_CONNECTION_HANDLER_I
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
initialize
|
||||
local
|
||||
n: INTEGER
|
||||
p: like pool
|
||||
do
|
||||
n := max_concurrent_connections (server).max (1) -- At least one processor!
|
||||
create p.make (n)
|
||||
initialize_pool (p, n)
|
||||
pool := p
|
||||
end
|
||||
|
||||
initialize_pool (p: like pool; n: INTEGER)
|
||||
-- Initialize Concurrent pool of `n' potential separate connection handlers.
|
||||
do
|
||||
p.set_count (n)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
is_shutdown_requested: BOOLEAN
|
||||
-- <Precursor>
|
||||
|
||||
max_concurrent_connections (a_server: like server): INTEGER
|
||||
-- Max concurrent connection settings from server `a_server'.
|
||||
do
|
||||
Result := a_server.configuration.max_concurrent_connections
|
||||
end
|
||||
|
||||
feature {HTTPD_SERVER_I} -- Execution
|
||||
|
||||
shutdown
|
||||
-- <Precursor>
|
||||
do
|
||||
if not is_shutdown_requested then
|
||||
is_shutdown_requested := True
|
||||
pool_gracefull_stop (pool)
|
||||
end
|
||||
end
|
||||
|
||||
pool_gracefull_stop (p: like pool)
|
||||
-- Graceful stop concurrent pool of separate connection handlers.
|
||||
do
|
||||
p.gracefull_stop
|
||||
end
|
||||
|
||||
accept_incoming_connection (a_listening_socket: HTTPD_STREAM_SOCKET)
|
||||
-- <Precursor>
|
||||
do
|
||||
accept_connection_on_pool (pool, a_listening_socket) -- Wait on not pool.is_full or is_stop_requested
|
||||
end
|
||||
|
||||
accept_connection_on_pool (a_pool: like pool; a_listening_socket: HTTPD_STREAM_SOCKET)
|
||||
-- Process accept connection
|
||||
-- note that the precondition matters for scoop synchronization.
|
||||
require
|
||||
concurrency: not a_pool.is_full or is_shutdown_requested or a_pool.stop_requested
|
||||
local
|
||||
cl: separate HTTPD_STREAM_SOCKET
|
||||
do
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".ENTER accept_connection_on_pool")
|
||||
end
|
||||
if is_shutdown_requested then
|
||||
-- Cancel
|
||||
elseif attached a_pool.separate_item (factory) as h then
|
||||
cl := separate_client_socket (h)
|
||||
a_listening_socket.accept_to (cl)
|
||||
process_handler (h)
|
||||
else
|
||||
check is_not_full: False end
|
||||
end
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".LEAVE accept_connection_on_pool")
|
||||
end
|
||||
end
|
||||
|
||||
process_handler (hdl: separate HTTPD_REQUEST_HANDLER)
|
||||
-- Process request handler `hdl' as soon as `hdl' is connected to accepted socket.
|
||||
require
|
||||
hdl.is_connected
|
||||
do
|
||||
hdl.safe_execute
|
||||
end
|
||||
|
||||
feature {HTTPD_SERVER_I} -- Status report
|
||||
|
||||
wait_for_completion
|
||||
-- Wait until Current is ready for shutdown.
|
||||
do
|
||||
wait_for_pool_completion (pool)
|
||||
end
|
||||
|
||||
wait_for_pool_completion (p: like pool)
|
||||
-- Wait until concurrent pool is empty and terminated.
|
||||
require
|
||||
p.is_empty -- SCOOP wait condition.
|
||||
do
|
||||
p.terminate
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
separate_client_socket (hdl: separate HTTPD_REQUEST_HANDLER): separate HTTPD_STREAM_SOCKET
|
||||
-- Client socket for request handler `hdl'.
|
||||
do
|
||||
Result := hdl.client_socket
|
||||
end
|
||||
|
||||
pool: separate CONCURRENT_POOL [HTTPD_REQUEST_HANDLER]
|
||||
-- Pool of separate connection handlers.
|
||||
|
||||
invariant
|
||||
pool_attached: pool /= Void
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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
|
||||
@@ -0,0 +1,62 @@
|
||||
note
|
||||
description: "[
|
||||
Instance of HTTPD_REQUEST_HANDLER will process the incoming connection
|
||||
and extract information on the request and the server
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_REQUEST_HANDLER
|
||||
|
||||
inherit
|
||||
HTTPD_REQUEST_HANDLER_I
|
||||
redefine
|
||||
release
|
||||
end
|
||||
|
||||
CONCURRENT_POOL_ITEM
|
||||
rename
|
||||
release as release_pool_item
|
||||
end
|
||||
|
||||
feature {CONCURRENT_POOL, HTTPD_CONNECTION_HANDLER_I} -- Basic operation
|
||||
|
||||
release
|
||||
-- <Precursor>
|
||||
local
|
||||
d: detachable STRING
|
||||
do
|
||||
debug ("dbglog")
|
||||
if
|
||||
attached internal_client_socket as l_socket and then
|
||||
l_socket.descriptor_available
|
||||
then
|
||||
d := l_socket.descriptor.out
|
||||
else
|
||||
d := "N/A"
|
||||
end
|
||||
dbglog (generator + ".release: ENTER {" + d + "}")
|
||||
end
|
||||
Precursor {HTTPD_REQUEST_HANDLER_I}
|
||||
release_pool_item
|
||||
debug ("dbglog")
|
||||
if d /= Void then
|
||||
dbglog (generator + ".release: LEAVE {" + d + "}")
|
||||
else
|
||||
dbglog (generator + ".release: LEAVE {N/A}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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
|
||||
@@ -0,0 +1,27 @@
|
||||
note
|
||||
description: "Implementation of request handler factory for concurrency mode: SCOOP"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_REQUEST_HANDLER_FACTORY
|
||||
|
||||
inherit
|
||||
HTTPD_REQUEST_HANDLER_FACTORY_I
|
||||
|
||||
CONCURRENT_POOL_FACTORY [HTTPD_REQUEST_HANDLER]
|
||||
rename
|
||||
new_separate_item as new_handler
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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
|
||||
190
library/server/httpd/concurrency/scoop/pool/concurrent_pool.e
Normal file
190
library/server/httpd/concurrency/scoop/pool/concurrent_pool.e
Normal file
@@ -0,0 +1,190 @@
|
||||
note
|
||||
description: "Concurrent pool for SCOOP concurrency mode."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
CONCURRENT_POOL [G -> CONCURRENT_POOL_ITEM]
|
||||
|
||||
inherit
|
||||
HTTPD_DEBUG_FACILITIES
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (n: INTEGER)
|
||||
do
|
||||
capacity := n
|
||||
create items.make_empty (n)
|
||||
create busy_items.make_empty (n)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
count: INTEGER
|
||||
-- Number of concurrent items managed by Current pool.
|
||||
|
||||
capacity: INTEGER
|
||||
-- Maximum number of concurrent items managed by Current pool.
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_full: BOOLEAN
|
||||
-- Pool is full?
|
||||
do
|
||||
Result := count >= capacity
|
||||
end
|
||||
|
||||
is_empty: BOOLEAN
|
||||
-- No concurrent item waiting in current pool.
|
||||
do
|
||||
Result := count = 0
|
||||
end
|
||||
|
||||
stop_requested: BOOLEAN
|
||||
-- Current pool received a request to terminate.
|
||||
|
||||
feature -- Access
|
||||
|
||||
separate_item (a_factory: separate CONCURRENT_POOL_FACTORY [G]): detachable separate G
|
||||
-- Reused, or new separate item of type {G} created by `a_factory'.
|
||||
require
|
||||
is_not_full: not is_full
|
||||
local
|
||||
i,n,pos: INTEGER
|
||||
lst: like busy_items
|
||||
l_item: detachable separate G
|
||||
do
|
||||
if not stop_requested then
|
||||
from
|
||||
lst := busy_items
|
||||
pos := -1
|
||||
i := 0
|
||||
n := lst.count - 1
|
||||
until
|
||||
i > n or l_item /= Void or pos >= 0
|
||||
loop
|
||||
if not lst [i] then -- is free (i.e not busy)
|
||||
pos := i
|
||||
|
||||
if items.valid_index (pos) then
|
||||
l_item := items [pos]
|
||||
if l_item /= Void then
|
||||
busy_items [pos] := True
|
||||
end
|
||||
end
|
||||
if l_item = Void then
|
||||
-- Empty, then let's create one.
|
||||
l_item := a_factory.new_separate_item
|
||||
register_item (l_item)
|
||||
items [pos] := l_item
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
if l_item = Void then
|
||||
-- Pool is FULL ...
|
||||
check overcapacity: False end
|
||||
else
|
||||
debug ("pool", "dbglog")
|
||||
dbglog ("Lock pool item #" + pos.out + " (free:"+ (capacity - count).out +"))")
|
||||
end
|
||||
count := count + 1
|
||||
busy_items [pos] := True
|
||||
Result := l_item
|
||||
a_factory.update_item (l_item)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
gracefull_stop
|
||||
-- Request the Current pool to terminate.
|
||||
do
|
||||
stop_requested := True
|
||||
end
|
||||
|
||||
feature {NONE} -- Internal
|
||||
|
||||
items: SPECIAL [detachable separate G]
|
||||
-- List of concurrent items.
|
||||
|
||||
busy_items: SPECIAL [BOOLEAN]
|
||||
-- Map of items being proceed.
|
||||
|
||||
feature {CONCURRENT_POOL_ITEM} -- Change
|
||||
|
||||
release_item (a_item: separate G)
|
||||
-- Unregister `a_item' from Current pool.
|
||||
require
|
||||
count > 0
|
||||
local
|
||||
i,n,pos: INTEGER
|
||||
lst: like items
|
||||
do
|
||||
-- release handler for reuse
|
||||
from
|
||||
lst := items
|
||||
i := 0
|
||||
n := lst.count - 1
|
||||
until
|
||||
i > n or lst [i] = a_item
|
||||
loop
|
||||
i := i + 1
|
||||
end
|
||||
if i <= n then
|
||||
pos := i
|
||||
busy_items [pos] := False
|
||||
count := count - 1
|
||||
--reuse items [pos] := Void
|
||||
debug ("pool", "dbglog")
|
||||
dbglog ("Released pool item #" + i.out + " (free:"+ (capacity - count).out +"))")
|
||||
end
|
||||
else
|
||||
check known_item: False end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Change
|
||||
|
||||
set_count (n: INTEGER)
|
||||
-- Set capacity of Current pool to `n'.
|
||||
local
|
||||
g: detachable separate G
|
||||
do
|
||||
capacity := n
|
||||
items.fill_with (g, 0, n - 1)
|
||||
busy_items.fill_with (False, 0, n - 1)
|
||||
end
|
||||
|
||||
terminate
|
||||
-- Terminate current pool.
|
||||
local
|
||||
l_items: like items
|
||||
do
|
||||
l_items := items
|
||||
l_items.wipe_out
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
register_item (a_item: separate G)
|
||||
-- Adopt `a_item' in current pool.
|
||||
do
|
||||
a_item.set_pool (Current)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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
|
||||
@@ -0,0 +1,31 @@
|
||||
note
|
||||
description: "Factory in charge of creating new concurrent pool item."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
CONCURRENT_POOL_FACTORY [G -> CONCURRENT_POOL_ITEM]
|
||||
|
||||
feature -- Access
|
||||
|
||||
update_item (a_item: separate G)
|
||||
-- Update `a_item' for optionally purpose.
|
||||
do
|
||||
end
|
||||
|
||||
new_separate_item: separate G
|
||||
-- New separated object of type {G}.
|
||||
deferred
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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
|
||||
@@ -0,0 +1,52 @@
|
||||
note
|
||||
description: "[
|
||||
Item create by the CONCURRENT_POOL_FACTORY, and managed by the CONCURRENT_POOL
|
||||
for SCOOP concurrency mode.
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
CONCURRENT_POOL_ITEM
|
||||
|
||||
feature {NONE} -- Access
|
||||
|
||||
pool: detachable separate CONCURRENT_POOL [CONCURRENT_POOL_ITEM]
|
||||
-- Associated concurrent pool component.
|
||||
|
||||
feature {CONCURRENT_POOL} -- Change
|
||||
|
||||
set_pool (p: like pool)
|
||||
-- Set associated `pool' to `p'.
|
||||
do
|
||||
pool := p
|
||||
end
|
||||
|
||||
feature {CONCURRENT_POOL, HTTPD_CONNECTION_HANDLER_I} -- Basic operation
|
||||
|
||||
release
|
||||
-- Release Current pool item from associated pool.
|
||||
do
|
||||
if attached pool as p then
|
||||
pool_release (p)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
pool_release (p: separate CONCURRENT_POOL [CONCURRENT_POOL_ITEM])
|
||||
do
|
||||
p.release_item (Current)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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
|
||||
@@ -0,0 +1,103 @@
|
||||
note
|
||||
description: "[
|
||||
Implementation of HTTPD_CONNECTION_HANDLER_I for concurrency mode: Thread
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HTTPD_CONNECTION_HANDLER
|
||||
|
||||
inherit
|
||||
HTTPD_CONNECTION_HANDLER_I
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
initialize
|
||||
local
|
||||
n: INTEGER
|
||||
do
|
||||
n := max_concurrent_connections (server).max (1) -- At least one thread!
|
||||
create pool.make (n.to_natural_32)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
is_shutdown_requested: BOOLEAN
|
||||
|
||||
max_concurrent_connections (a_server: like server): INTEGER
|
||||
do
|
||||
Result := a_server.configuration.max_concurrent_connections
|
||||
end
|
||||
|
||||
feature {HTTPD_SERVER_I} -- Execution
|
||||
|
||||
shutdown
|
||||
do
|
||||
if not is_shutdown_requested then
|
||||
is_shutdown_requested := True
|
||||
pool_gracefull_stop (pool)
|
||||
end
|
||||
end
|
||||
|
||||
pool_gracefull_stop (p: like pool)
|
||||
do
|
||||
p.terminate
|
||||
end
|
||||
|
||||
accept_incoming_connection (a_listening_socket: HTTPD_STREAM_SOCKET)
|
||||
local
|
||||
cl: separate HTTPD_STREAM_SOCKET
|
||||
do
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".ENTER accept_connection {"+ a_listening_socket.descriptor.out +"}")
|
||||
end
|
||||
|
||||
if is_shutdown_requested then
|
||||
-- cancel
|
||||
elseif attached factory.new_handler as h then
|
||||
cl := h.client_socket
|
||||
a_listening_socket.accept_to (cl)
|
||||
if h.is_connected then
|
||||
pool.add_work (agent h.safe_execute)
|
||||
end
|
||||
end
|
||||
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".LEAVE accept_incoming_connection {"+ a_listening_socket.descriptor.out +"}")
|
||||
end
|
||||
end
|
||||
|
||||
feature {HTTPD_SERVER_I} -- Status report
|
||||
|
||||
wait_for_completion
|
||||
-- Wait until Current is ready for shutdown
|
||||
do
|
||||
pool.wait_for_completion
|
||||
end
|
||||
|
||||
feature {NONE} -- Access
|
||||
|
||||
pool: THREAD_POOL [HTTPD_REQUEST_HANDLER] --ANY] --POOLED_THREAD [HTTP_REQUEST_HANDLER]]
|
||||
-- Pool of concurrent connection handlers.
|
||||
|
||||
invariant
|
||||
pool_attached: pool /= Void
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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
|
||||
@@ -0,0 +1,56 @@
|
||||
note
|
||||
description: "[
|
||||
Instance of HTTPD_REQUEST_HANDLER will process the incoming connection
|
||||
and extract information on the request and the server
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_REQUEST_HANDLER
|
||||
|
||||
inherit
|
||||
HTTPD_REQUEST_HANDLER_I
|
||||
redefine
|
||||
release
|
||||
end
|
||||
|
||||
feature {HTTPD_CONNECTION_HANDLER_I} -- Basic operation
|
||||
|
||||
release
|
||||
-- <Precursor>
|
||||
local
|
||||
d: detachable STRING
|
||||
do
|
||||
debug ("dbglog")
|
||||
if
|
||||
attached internal_client_socket as l_socket and then
|
||||
l_socket.descriptor_available
|
||||
then
|
||||
d := l_socket.descriptor.out
|
||||
else
|
||||
d := "N/A"
|
||||
end
|
||||
dbglog (generator + ".release: ENTER {" + d + "}")
|
||||
end
|
||||
Precursor {HTTPD_REQUEST_HANDLER_I}
|
||||
debug ("dbglog")
|
||||
if d /= Void then
|
||||
dbglog (generator + ".release: LEAVE {" + d + "}")
|
||||
else
|
||||
dbglog (generator + ".release: LEAVE {N/A}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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
|
||||
@@ -0,0 +1,15 @@
|
||||
note
|
||||
description: "Implementation of request handler factory for concurrency mode: Thread"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_REQUEST_HANDLER_FACTORY
|
||||
|
||||
inherit
|
||||
HTTPD_REQUEST_HANDLER_FACTORY_I
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
121
library/server/httpd/concurrency/thread/pool/pooled_thread.e
Normal file
121
library/server/httpd/concurrency/thread/pool/pooled_thread.e
Normal file
@@ -0,0 +1,121 @@
|
||||
note
|
||||
description: "{POOLED_THREAD} is used in combination with {THREAD_POOL} to allow for pooled threads."
|
||||
legal: "See notice at end of class."
|
||||
status: "Community Preview 1.0"
|
||||
date: "$Date: 2009-09-01 19:15:37 -0300 (mar 01 de sep de 2009) $"
|
||||
revision: "$Revision: 80577 $"
|
||||
|
||||
class
|
||||
POOLED_THREAD [G]
|
||||
|
||||
inherit
|
||||
THREAD
|
||||
rename
|
||||
make as thread_make
|
||||
end
|
||||
|
||||
create {THREAD_POOL}
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_thread_pool: THREAD_POOL [G]; a_semaphore: SEMAPHORE)
|
||||
-- `a_thread_pool', the pool in which this thread is managed
|
||||
-- `a_semaphore' is used for execution suspending
|
||||
do
|
||||
thread_make
|
||||
thread_pool := a_thread_pool
|
||||
semaphore := a_semaphore
|
||||
end
|
||||
|
||||
feature {NONE} -- Access
|
||||
|
||||
thread_pool: THREAD_POOL [G]
|
||||
-- Pool manager in which this thread is pooled
|
||||
|
||||
target: detachable G
|
||||
-- Target on which the `thread_procedure' should be applied
|
||||
-- Depending on which launch is used, target is not used
|
||||
|
||||
thread_procedure: detachable PROCEDURE
|
||||
-- Work that should be executed by the thread
|
||||
|
||||
semaphore: SEMAPHORE
|
||||
-- Semaphore share with all threads in a thread pool
|
||||
-- to suspend execution until more work is available
|
||||
|
||||
feature -- Access
|
||||
|
||||
set_target (a_target: G)
|
||||
-- Sets the target on which the work should be executed
|
||||
do
|
||||
target := a_target
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
execute
|
||||
-- <Precursor>
|
||||
local
|
||||
done: BOOLEAN
|
||||
do
|
||||
from
|
||||
semaphore.wait
|
||||
thread_procedure := thread_pool.get_work (Current)
|
||||
until
|
||||
done
|
||||
loop
|
||||
if attached thread_procedure as l_work then
|
||||
if attached target as t then
|
||||
l_work.call ([t])
|
||||
else
|
||||
l_work.call (Void)
|
||||
end
|
||||
end
|
||||
if thread_pool.over then
|
||||
done := True
|
||||
else
|
||||
thread_procedure := thread_pool.get_work (Current)
|
||||
if thread_procedure = Void then
|
||||
semaphore.wait
|
||||
thread_procedure := thread_pool.get_work (Current)
|
||||
end
|
||||
end
|
||||
end
|
||||
thread_pool.thread_terminated (Current)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
licensing_options: "http://www.eiffel.com/licensing"
|
||||
copying: "[
|
||||
This file is part of Eiffel Software's Eiffel Development Environment.
|
||||
|
||||
Eiffel Software's Eiffel Development Environment is free
|
||||
software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation, version 2 of the License
|
||||
(available at the URL listed under "license" above).
|
||||
|
||||
Eiffel Software's Eiffel Development Environment is
|
||||
distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with Eiffel Software's Eiffel Development
|
||||
Environment; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
]"
|
||||
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
|
||||
|
||||
|
||||
228
library/server/httpd/concurrency/thread/pool/thread_pool.e
Normal file
228
library/server/httpd/concurrency/thread/pool/thread_pool.e
Normal file
@@ -0,0 +1,228 @@
|
||||
note
|
||||
description: "[
|
||||
A thread pool manager. Manages threads up to `capacity' and queue after that,
|
||||
till threads get available again.
|
||||
]"
|
||||
legal: "See notice at end of class."
|
||||
status: "Community Preview 1.0"
|
||||
date: "$Date: 2009-09-01 19:15:37 -0300 (mar 01 de sep de 2009) $"
|
||||
revision: "$Revision: 80577 $"
|
||||
|
||||
class
|
||||
THREAD_POOL [G]
|
||||
|
||||
inherit
|
||||
EXECUTION_ENVIRONMENT
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (n: like capacity)
|
||||
-- Initialize current pool with capacity `n'.
|
||||
require
|
||||
n_positive: n > 0
|
||||
n_not_too_large: n < {INTEGER_32}.max_value.as_natural_32
|
||||
local
|
||||
i: NATURAL
|
||||
do
|
||||
capacity := n
|
||||
create work_queue.make (n.to_integer_32)
|
||||
create work_queue_mutex.make
|
||||
create over_mutex.make
|
||||
create termination_mutex.make
|
||||
create work_semaphore.make (capacity.as_integer_32)
|
||||
from
|
||||
i := 1
|
||||
until
|
||||
i > capacity
|
||||
loop
|
||||
work_semaphore.wait
|
||||
i := i + 1
|
||||
end
|
||||
initialize_threads
|
||||
terminated_count := capacity
|
||||
is_over := False
|
||||
ensure
|
||||
capacity_set: capacity = n
|
||||
work_queue_set: work_queue.is_empty
|
||||
end
|
||||
|
||||
initialize_threads
|
||||
-- Launches all threads
|
||||
local
|
||||
i: NATURAL
|
||||
thread: POOLED_THREAD [G]
|
||||
do
|
||||
from
|
||||
i := 1
|
||||
until
|
||||
i > capacity
|
||||
loop
|
||||
create thread.make (Current, work_semaphore)
|
||||
thread.launch
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
capacity: NATURAL
|
||||
-- Maximal number of threads allowed (queuing otherwise)
|
||||
|
||||
queue_count: NATURAL
|
||||
-- Number of items in queue
|
||||
do
|
||||
work_queue_mutex.lock
|
||||
Result := work_queue.count.as_natural_32
|
||||
work_queue_mutex.unlock
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
valid_action (a_action: PROCEDURE): BOOLEAN
|
||||
-- Is `a_action' a valid action for the current pool.
|
||||
do
|
||||
-- There should be no open operands.
|
||||
Result := a_action.valid_operands (Void)
|
||||
end
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
add_work (work: PROCEDURE)
|
||||
-- Launches a thread with the specified argument `arg'. Reuse of thread if possible.
|
||||
require
|
||||
valid_action: valid_action (work)
|
||||
do
|
||||
work_queue_mutex.lock
|
||||
work_queue.extend (work)
|
||||
if work_queue.count <= capacity.as_integer_32 then
|
||||
-- Let one thread wake up and do the work
|
||||
work_semaphore.post
|
||||
end
|
||||
work_queue_mutex.unlock
|
||||
end
|
||||
|
||||
over: BOOLEAN
|
||||
-- Is the thread pool being terminated?
|
||||
do
|
||||
over_mutex.lock
|
||||
Result := is_over
|
||||
over_mutex.unlock
|
||||
end
|
||||
|
||||
thread_terminated (a_thread: POOLED_THREAD [G])
|
||||
-- Notifies the thread pool that a thread has terminated its execution.
|
||||
do
|
||||
termination_mutex.lock
|
||||
terminated_count := terminated_count - 1
|
||||
termination_mutex.unlock
|
||||
end
|
||||
|
||||
get_work (requester: POOLED_THREAD [G]): detachable PROCEDURE
|
||||
-- If there is work to do, it is returned
|
||||
-- Yields Void otherwise
|
||||
do
|
||||
if not over then
|
||||
work_queue_mutex.lock
|
||||
if not work_queue.is_empty then
|
||||
Result := work_queue.item
|
||||
work_queue.remove
|
||||
end
|
||||
work_queue_mutex.unlock
|
||||
end
|
||||
end
|
||||
|
||||
wait_for_completion
|
||||
-- Wait until there is no more work to be completed
|
||||
local
|
||||
done: BOOLEAN
|
||||
do
|
||||
from
|
||||
|
||||
until
|
||||
done
|
||||
loop
|
||||
work_queue_mutex.lock
|
||||
done := work_queue.is_empty
|
||||
work_queue_mutex.unlock
|
||||
if not done then
|
||||
sleep (1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
terminate
|
||||
-- Terminates all the threads after their execution
|
||||
do
|
||||
over_mutex.lock
|
||||
is_over := True
|
||||
over_mutex.unlock
|
||||
from
|
||||
termination_mutex.lock
|
||||
until
|
||||
terminated_count = 0
|
||||
loop
|
||||
work_semaphore.post
|
||||
termination_mutex.unlock
|
||||
termination_mutex.lock
|
||||
end
|
||||
termination_mutex.unlock
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation: Access
|
||||
|
||||
work_queue: ARRAYED_QUEUE [PROCEDURE]
|
||||
-- Queue that holds unprocessed requests as agents
|
||||
-- Thread-safe access when accessor holds `queue_mutex'
|
||||
|
||||
work_queue_mutex: MUTEX
|
||||
-- Mutex for the queue
|
||||
|
||||
work_semaphore: SEMAPHORE
|
||||
-- Semaphore which hols the number of work to be done.
|
||||
-- Needed to wake up worker threads
|
||||
|
||||
terminated_count: NATURAL
|
||||
--
|
||||
|
||||
is_over: BOOLEAN
|
||||
-- Is the thread pool being terminated?
|
||||
|
||||
over_mutex: MUTEX
|
||||
-- Mutex for the `is_over' variable
|
||||
|
||||
termination_mutex: MUTEX
|
||||
;note
|
||||
copyright: "2011-2012, Javier Velilla, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
licensing_options: "http://www.eiffel.com/licensing"
|
||||
copying: "[
|
||||
This file is part of Eiffel Software's Eiffel Development Environment.
|
||||
|
||||
Eiffel Software's Eiffel Development Environment is free
|
||||
software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation, version 2 of the License
|
||||
(available at the URL listed under "license" above).
|
||||
|
||||
Eiffel Software's Eiffel Development Environment is
|
||||
distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with Eiffel Software's Eiffel Development
|
||||
Environment; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
]"
|
||||
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
|
||||
Reference in New Issue
Block a user