comp.lang.ada
 help / color / mirror / Atom feed
* copy constructor for sockets
@ 2004-05-22 10:19 Andrew Carroll
  2004-05-22 11:55 ` Simon Wright
  0 siblings, 1 reply; 21+ messages in thread
From: Andrew Carroll @ 2004-05-22 10:19 UTC (permalink / raw)
  To: comp.lang.ada

I am wondering if it is possible to write a copy constructor for a
socket.
I did not see one in AdaSockets however I have never written a "copy
constructor" in Ada so I probably wouldn't know what to look for.

Maybe it violates some standard for socket communication to have a copy
constructor for a socket?

Just curious.

Andrew




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: copy constructor for sockets
  2004-05-22 10:19 Andrew Carroll
@ 2004-05-22 11:55 ` Simon Wright
  2004-05-22 18:39   ` tmoran
  2004-05-23 21:04   ` Matthew Heaney
  0 siblings, 2 replies; 21+ messages in thread
From: Simon Wright @ 2004-05-22 11:55 UTC (permalink / raw)


"Andrew Carroll" <andrew@carroll-tech.net> writes:

> I am wondering if it is possible to write a copy constructor for a
> socket.
> I did not see one in AdaSockets however I have never written a "copy
> constructor" in Ada so I probably wouldn't know what to look for.
> 
> Maybe it violates some standard for socket communication to have a
> copy constructor for a socket?

You have to decide what you want your copy to do!

If you just want to pass the socket around, a plain copy will do
fine. But of course you need to decide what the semantics are.

Copying where one copy is used for read & the other for write is fine,
sockets are like that.

But if you have copies where each is used for reading or writing you
have application-level protocol problems you have to decide:

* is it the same write socket? (ie, the guy at the other end is still
  there and you have two writers): then you'd better be sure your
  sockets are thread-safe (VxWorks stock ones aren't, to my surprise,
  so a single large send(2) can get split). Or you could ensure
  exclusive access with a mutex of some sort.

* is it the same read socket? (ie, only one guy at the other end, you
  are supplying multiple read tasks): better be sure you can split the
  input stream at logical record boundaries.

* do you want a new stream to a new remote process? then it's all got
  _much_ more complicated.

And it'll be a matter of application policy, far too specific to
delegate to a low-level socket abstraction; you'd need to make your
own higher-level abstraction.

-- 
Simon Wright                               100% Ada, no bugs.



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: copy constructor for sockets
  2004-05-22 11:55 ` Simon Wright
@ 2004-05-22 18:39   ` tmoran
  2004-05-23 21:04   ` Matthew Heaney
  1 sibling, 0 replies; 21+ messages in thread
From: tmoran @ 2004-05-22 18:39 UTC (permalink / raw)


What happens when one of the copies is "closed" and then someone "writes"
on the other?  Or worse, is closed, then reopened with a different remote
connection.  A socket is in some ways like a pointer to a (remote) data
object - it's always living dangerously to have multiple independent
pointers to the same object.



^ permalink raw reply	[flat|nested] 21+ messages in thread

* copy constructor for sockets
@ 2004-05-22 21:18 Andrew Carroll
  2004-05-22 21:46 ` tmoran
                   ` (2 more replies)
  0 siblings, 3 replies; 21+ messages in thread
From: Andrew Carroll @ 2004-05-22 21:18 UTC (permalink / raw)
  To: comp.lang.ada

Okay,

I have written a small test server.  All it does is Accept() connections
and Get_line() and then a final Get().  It is just an experiment but I
want the server now to create a task (with a socket as one of it's
members) and initialize that socket.  There are two types of tasks
however and the distinction between which task to create comes from the
header information in the get_line() right after the Accept().  If it is
a GET header then I would create task type A, if it is a POST then I
would create task type B.

So, the server must accept the socket and do an initial read to get the
header information (GET or POST) to know which type of task to create.
Then I want to initialize the socket that is in the task type to be the
same as the socket in the server that was just accepted.  It would
probably need to be a "deep copy" of the socket because the server will
need to release the socket and the task will need to keep the socket.
By release I mean close() and by keep I mean use for communication.

The other option is to use an access yet I think it could be done
without it.

Doesn't the ":=" operator to a "deep copy"?

Andrew





^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: copy constructor for sockets
  2004-05-22 21:18 Andrew Carroll
@ 2004-05-22 21:46 ` tmoran
  2004-05-23 11:21   ` Simon Wright
  2004-05-23  9:43 ` Mark Lorenzen
  2004-05-23 11:27 ` Simon Wright
  2 siblings, 1 reply; 21+ messages in thread
From: tmoran @ 2004-05-22 21:46 UTC (permalink / raw)


>So, the server must accept the socket and do an initial read to get the
>header information (GET or POST) to know which type of task to create.
>Then I want to initialize the socket that is in the task type to be the
>same as the socket in the server that was just accepted.  It would
>probably need to be a "deep copy" of the socket because the server will
>need to release the socket and the task will need to keep the socket.
>By release I mean close() and by keep I mean use for communication.

Remember that a task is a thread of control, not a sequence of
instructions.  From that viewpoint, your server needs to fire up a
task/thread, and that thread needs to find out whether it should execute
the Get or the Put sequence of instructions.  You can pass the server
socket to the task during the rendezvous, and let the task create a socket
and do the socket-accept.  That lets the server get back to waiting for
calls as quickly as possible, while the task does the Get_Line (which
could potentially take a while) and calls an appropriate Handle_Get or
Handle_Post procedure.  You can see an example of this in Smplsrvr (part
of the free Claw download at www.rrsoftware.com).  You might also want to
see how AWS does it.

> Doesn't the ":=" operator to a "deep copy"?
If the object is Limited, ":=" is illegal.  (That's the case for Claw
Sockets.) If it's Controlled, then ":=" does a bit pattern copy followed
by a call on Adjust, which may do nothing, may modify pointers or
whatever, or may do a deep copy - whatever it wants.  If the object is not
Controlled, and isn't Limited, then ":=" just does a bitwise copy.



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: copy constructor for sockets
  2004-05-22 21:18 Andrew Carroll
  2004-05-22 21:46 ` tmoran
@ 2004-05-23  9:43 ` Mark Lorenzen
  2004-05-23 11:27 ` Simon Wright
  2 siblings, 0 replies; 21+ messages in thread
From: Mark Lorenzen @ 2004-05-23  9:43 UTC (permalink / raw)


"Andrew Carroll" <andrew@carroll-tech.net> writes:

> Okay,
>
> I have written a small test server.  All it does is Accept() connections
> and Get_line() and then a final Get().  It is just an experiment but I
> want the server now to create a task (with a socket as one of it's
> members) and initialize that socket.  There are two types of tasks
> however and the distinction between which task to create comes from the
> header information in the get_line() right after the Accept().  If it is
> a GET header then I would create task type A, if it is a POST then I
> would create task type B.
>
> So, the server must accept the socket and do an initial read to get the
> header information (GET or POST) to know which type of task to create.
> Then I want to initialize the socket that is in the task type to be the
> same as the socket in the server that was just accepted.  It would
> probably need to be a "deep copy" of the socket because the server will
> need to release the socket and the task will need to keep the socket.
> By release I mean close() and by keep I mean use for communication.
>
> The other option is to use an access yet I think it could be done
> without it.
>
> Doesn't the ":=" operator to a "deep copy"?
>
> Andrew

This design is enough if you have a small number of connections. If
you want to design a high performance server application with
thousands of connections, you must reduce the use of tasks as the
system will drown in conext switches otherwise.


Some links with good info:

http://pl.atyp.us/content/tech/servers.html

http://www.kegel.com/c10k.html

But remember, if you are only learning to design a server application,
then you should not bother about performance with thousands of
connections yet. It is better to learn UNIX socket communication
first.

- Mark Lorenzen



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: copy constructor for sockets
  2004-05-22 21:46 ` tmoran
@ 2004-05-23 11:21   ` Simon Wright
  2004-05-24 18:26     ` tmoran
  0 siblings, 1 reply; 21+ messages in thread
From: Simon Wright @ 2004-05-23 11:21 UTC (permalink / raw)


tmoran@acm.org writes:

> Remember that a task is a thread of control, not a sequence of
> instructions.  From that viewpoint, your server needs to fire up a
> task/thread, and that thread needs to find out whether it should execute
> the Get or the Put sequence of instructions.  You can pass the server
> socket to the task during the rendezvous, and let the task create a socket
> and do the socket-accept.

Is it really possible to have multiple accept()s? You live and learn!
(I thought you could only have one accept(), which blocks until a
client connect()s and then returns a new socket ... so, with your
design, what is the server doing while the task calls accept()?

I know you can use select() or poll() to block until an accept() would
succeed, is that the idea?

>                            That lets the server get back to waiting for
> calls as quickly as possible, while the task does the Get_Line (which
> could potentially take a while) and calls an appropriate Handle_Get or
> Handle_Post procedure.  You can see an example of this in Smplsrvr (part
> of the free Claw download at www.rrsoftware.com).  You might also want to
> see how AWS does it.
> 
> > Doesn't the ":=" operator to a "deep copy"?
> If the object is Limited, ":=" is illegal.  (That's the case for Claw
> Sockets.) If it's Controlled, then ":=" does a bit pattern copy followed
> by a call on Adjust, which may do nothing, may modify pointers or
> whatever, or may do a deep copy - whatever it wants.  If the object is not
> Controlled, and isn't Limited, then ":=" just does a bitwise copy.

That applies recursively to components, of course (remembering that a
type with limited components has to be limited, of course).

I don't know AdaSockets, but GNAT.Sockets (3.15p) has

   type Socket_Type is private;

which means that assignment is available, and, in the private part,

   type Socket_Type is new Integer;

and in the body (eg)

   procedure Accept_Socket
     (Server  : Socket_Type;
      Socket  : out Socket_Type;
      Address : out Sock_Addr_Type)
   is
      Res : C.int;
      Sin : aliased Sockaddr_In;
      Len : aliased C.int := Sin'Size / 8;

   begin
      Res := C_Accept (C.int (Server), Sin'Address, Len'Access);

      if Res = Failure then
         Raise_Socket_Error (Socket_Errno);
      end if;

      Socket := Socket_Type (Res);

      Address.Addr := To_Inet_Addr (Sin.Sin_Addr);
      Address.Port := Port_Type (Network_To_Port (Sin.Sin_Port));
   end Accept_Socket;

so you can see that it's extremely close to the C accept(2); the
socket is essentially a file descriptor, in Unix terms anyway.

So assignment works (for this binding) as it would in C.

-- 
Simon Wright                               100% Ada, no bugs.



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: copy constructor for sockets
  2004-05-22 21:18 Andrew Carroll
  2004-05-22 21:46 ` tmoran
  2004-05-23  9:43 ` Mark Lorenzen
@ 2004-05-23 11:27 ` Simon Wright
  2 siblings, 0 replies; 21+ messages in thread
From: Simon Wright @ 2004-05-23 11:27 UTC (permalink / raw)


"Andrew Carroll" <andrew@carroll-tech.net> writes:

> So, the server must accept the socket and do an initial read to get the
> header information (GET or POST) to know which type of task to create.
> Then I want to initialize the socket that is in the task type to be the
> same as the socket in the server that was just accepted.  It would
> probably need to be a "deep copy" of the socket because the server will
> need to release the socket and the task will need to keep the socket.
> By release I mean close() and by keep I mean use for communication.

You mustn't finally close() the socket you get back from the accept()
until you have sent your reply. The browser client is expecting you to
use it.

In C terms, you could dup() the socket, pass the result off to the
task, and close() the first socket, but it doesn't seem necessary here
-- might be a good idea when the thing that is going to talk over the
socket is a child process that you have fork()ed, so as to avoid a
file handle leak in the server process, but these are tasks so I don't
think that's likely to be a problem. Others will know more than I do
about this!

-- 
Simon Wright                               100% Ada, no bugs.



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: copy constructor for sockets
  2004-05-22 11:55 ` Simon Wright
  2004-05-22 18:39   ` tmoran
@ 2004-05-23 21:04   ` Matthew Heaney
  2004-05-24  7:13     ` Marius Amado Alves
  1 sibling, 1 reply; 21+ messages in thread
From: Matthew Heaney @ 2004-05-23 21:04 UTC (permalink / raw)


Simon Wright <simon@pushface.org> writes:

> And it'll be a matter of application policy, far too specific to
> delegate to a low-level socket abstraction; you'd need to make your
> own higher-level abstraction.

That's pretty much what I do: write your own abstraction on top of the
low-level primitive.  On Windows, a socket is just a HANDLE, and on Unix
a socket is just a file descriptor (small positive integer).  I always
write some kind of Socket type, with the handle as its representation.

I have such an abstraction, that uses reference counting to keep track
of how many references there are to the descriptor:

package Sockets is

   type Socket is private;
...
private

   type Rep_Type is record
      fd        : Interfaces.C.int;
      Ref_Count : Natural;
   end record;

   type Rep_Access is access Rep_Type;

   type Socket is new Controlled with record
      Rep : Rep_Access := new Rep_Type'(fd => -1, Ref_Count => 1);
   end record;
...
end Sockets;

Now you have assignment of sockets:

   S1 : Socket := S;

and during Adjust you increment the refcount of the socket.  You
decrement the refcount during Finalize.

You have to make choices specific to your application re the behavior of
Close -- can you close the file descriptor if there's more than one
reference to the socket?

I also include an operation like Close, but instead of closing the
socket, it dis-associates this socket object from the underlying
primitive:

procedure Detach (S : in out Socket) is
begin

   if S.Rep.Refcount = 1 then
      Close (S);
      return;
   end if;

   S.Rep.Refcount := S.Rep.Refcount - 1;
   --detach from old socket

   S.Rep := new Rep_Type'(fd => -1, Ref_Count => 1);
   --attach to fresh socket

end Detach;

This allows me to pass a socket around.  For example, I can create the
socket in one place, then hand it off to another abstraction somewhere
else:

procedure Initialize
  (Session : in out Session_Type;
   RTSP_Connection : in out Socket) is
begin
   Session.RTSP_Socket := RTSP_Connection;  --inc refcount
   Detach (RTSP_Connection);                --dec refcount
end;

Here I don't want to close the socket.  I merely give it to the Session
object, who assumes ownership.  The session object then closes the
socket later, during the Session's Finalize operation.

(From the point of view of the RTSP_Connection socket object, the socket
is closed, but of course the original socket hasn't been closed, because
it's now owned by the Session object, which continues to use it.)

I also provide a selector operation to get the file descriptor:

  function fd (S : Socket) return C.int;

This allows me to put the socket (really, its descriptor) in a map, say,
so that I can look up a session object, given a file descriptor.  This
is useful when handling delivery of a real-time signal.  The payload
provides the file descriptor, but I need a way to associate that with
the Session object containing that socket, for which the I/O completed.

See the latest release of the AI-302 draft for similar ideas:

<http://www.ada-auth.org/cgi-bin/cvsweb.cgi/AIs/AI-20302.TXT?rev=1.5>

-Matt




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: copy constructor for sockets
  2004-05-24  7:13     ` Marius Amado Alves
@ 2004-05-24  3:23       ` Matthew Heaney
  2004-05-24  4:53         ` Simon Wright
  0 siblings, 1 reply; 21+ messages in thread
From: Matthew Heaney @ 2004-05-24  3:23 UTC (permalink / raw)


"Marius Amado Alves" <amado.alves@netcabo.pt> writes:

> > ... during Adjust you increment the refcount of the socket.  You
> > decrement the refcount during Finalize.
> 
> Right. Now you only have to know how many times Finalize gets called,

Why?  When the refcount goes to zero, then the last of the socket
objects attached to that handle have been finalized, and you can
deallocate handle.  What's the problem?


> where from,

Why?  The whole point of using reference counting is to be able to
ignore when and by whom, because it is the socket object itself that
controls when the handle is closed.


> in which of these times you should decrement,

Huh?  Every time, of course.  How could it be otherwise?  What would a
reference counting scheme even mean, if you didn't decrement the
refcount during finalization of the object?


> and declare all sockets at library level.

Huh?  The sockets package is declared at library level, but socket
objects can be declared anywhere, at any level.


> A nice Rube Goldberg machine. Don't you just love the Ada way?

I'm not sure what you mean by "Ada way."  The code I described in my
last post was pseudo-code, translated from C++ code.  The reference
counting scheme I described is the same in either language.




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: copy constructor for sockets
  2004-05-24  3:23       ` Matthew Heaney
@ 2004-05-24  4:53         ` Simon Wright
  2004-05-24  5:20           ` tmoran
                             ` (2 more replies)
  0 siblings, 3 replies; 21+ messages in thread
From: Simon Wright @ 2004-05-24  4:53 UTC (permalink / raw)


Matthew Heaney <matthewjheaney@earthlink.net> writes:

> > in which of these times you should decrement,
> 
> Huh?  Every time, of course.  How could it be otherwise?  What would
> a reference counting scheme even mean, if you didn't decrement the
> refcount during finalization of the object?

I have it stuck in my head that Finalize can get called more than
once. Which would make a mockery of (simple-minded) reference counting
schemes, of course. Please tell me it ain't so! (or explain why it's
not actually a problem ..)

-- 
Simon Wright                               100% Ada, no bugs.



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: copy constructor for sockets
  2004-05-24  4:53         ` Simon Wright
@ 2004-05-24  5:20           ` tmoran
  2004-05-25  4:53             ` Simon Wright
  2004-05-24 12:36           ` Matthew Heaney
  2004-05-25 21:50           ` Robert I. Eachus
  2 siblings, 1 reply; 21+ messages in thread
From: tmoran @ 2004-05-24  5:20 UTC (permalink / raw)


>I have it stuck in my head that Finalize can get called more than
>once. Which would make a mockery of (simple-minded) reference counting
  If each copy of the socket points to the single shared ref count
(Rep_Type here), then Finalize may be called as often as you want on the
socket:  the first time it's called it decrements the shared reference
count, frees the Rep_Type if the count is now zero, and nulls the socket's
pointer.  Subsequent calls on the same socket see that the pointer is null
and there's nothing to do.



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: copy constructor for sockets
  2004-05-23 21:04   ` Matthew Heaney
@ 2004-05-24  7:13     ` Marius Amado Alves
  2004-05-24  3:23       ` Matthew Heaney
  0 siblings, 1 reply; 21+ messages in thread
From: Marius Amado Alves @ 2004-05-24  7:13 UTC (permalink / raw)
  To: comp.lang.ada

> ... during Adjust you increment the refcount of the socket.  You
> decrement the refcount during Finalize.

Right. Now you only have to know how many times Finalize gets called, where
from, in which of these times you should decrement, and declare all sockets
at library level. A nice Rube Goldberg machine. Don't you just love the Ada
way?




^ permalink raw reply	[flat|nested] 21+ messages in thread

* copy constructor for sockets
@ 2004-05-24 11:28 Andrew Carroll
  2004-05-25  5:29 ` Simon Wright
  0 siblings, 1 reply; 21+ messages in thread
From: Andrew Carroll @ 2004-05-24 11:28 UTC (permalink / raw)
  To: comp.lang.ada

Wow, GREAT information!!  Thanks all!!

Steve, Matthew, Marius:
Accept() does block, as you expected.  At least with AdaSockets.

I have three tasks.  One is the "accepting" task and the other two tasks
just do various work depending on the "method" of an HTTP header
(obtained from the first Get_Line(<socket>)).  So, accept() initializes
the socket, does one Get_Line(<socket>) and then if the method is GET,
then I want to pass the socket to task 'A'.  If the method is POST then
I want to pass the socket to task 'B'.  In both cases, I want the task
to provide the HTTP user with a response and close the socket.

All the "accepting" task does is initialize sockets and create new
tasks.  Well, it will do other things but right now I am just
experimenting.  Your select() or poll() idea is beautiful!  Because
then, when an accept would occur, I can have the tasks ('A' or 'B')
handle the whole "session".  Question now is, how do I know which task
to assign it to for handling?  I cannot get into the HTTP header before
I "accept".  Hmmmm....Anyway...

I once downloaded AWS but never really read about it because I was
looking into the source code for other things about an idea I had, of
which I gave up on.  I went back to read about AWS recently and it
provides the Callbacks and Method ?API? which would accomplish what I am
trying to achieve.  I haven't investigated "how" they did it and in fact
I would rather drudge through this for learning purposes, at least for a
while.

So, in the end I think I will ask permission to use AWS and skip the
"accepting" task in my design.  Then place the task 'A' and task 'B'
implementations in the Callback based on Method from AWS.  (forgive me,
I do not have the AWS documentation open to give accurate API names)

Never the less I am learning some great things.  You mentioned that a
socket is a file descriptor (Unix) and I'm not quite sure I fully
understand the implications of that.  I "heard" that sockets were
designed in such a way that it would be "transparent", like working with
files.  Does that mean I can do a seek() on a socket?  When people throw
out the term "file descriptor" and start talking about "small positive
integers" I draw a blank as to how those are used for "communication"
over a network device in general.  After all, there are MANY small
positive integers on my computer.  I'm assuming the file descriptor (fd)
means something to the OS?  So somewhere in the kernel or "shell"
interrupt handler there is an else if (//it is a small positive integer)
{ //must be a socket, fire-up the RS-232 driver}?

I thought a socket was an abstraction from an address?  For example. the
address to a UART or RS-232 PIC.  A driver of which is written (probably
a module) to control that device.  So how does a fd relate to that
driver?  Or are you saying that somewhere in my /dev directory there is
a directory entry for my UART?  I can just arbitrarily (at risk of
destruction) send data to the UART through an entry in the /dev
directory?

I guess I'm just trying to fill in the holes of what I have learned thus
far.  Or maybe more appropriately what I have failed to learn.

Thanks again!!

Andrew Carroll
Carroll-Tech
720-273-6814
andrew@carroll-tech.net




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: copy constructor for sockets
  2004-05-24  4:53         ` Simon Wright
  2004-05-24  5:20           ` tmoran
@ 2004-05-24 12:36           ` Matthew Heaney
  2004-05-25 21:50           ` Robert I. Eachus
  2 siblings, 0 replies; 21+ messages in thread
From: Matthew Heaney @ 2004-05-24 12:36 UTC (permalink / raw)


Simon Wright <simon@pushface.org> writes:

> I have it stuck in my head that Finalize can get called more than
> once. Which would make a mockery of (simple-minded) reference counting
> schemes, of course. Please tell me it ain't so! (or explain why it's
> not actually a problem ..)

That's OK because Finalize always sets its own rep ptr to null.  If
Finalize gets called again, then the ptr is null, in which case you do
nothing.





^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: copy constructor for sockets
  2004-05-23 11:21   ` Simon Wright
@ 2004-05-24 18:26     ` tmoran
  2004-05-25  5:10       ` Simon Wright
  0 siblings, 1 reply; 21+ messages in thread
From: tmoran @ 2004-05-24 18:26 UTC (permalink / raw)


>> socket to the task during the rendezvous, and let the task create a socket
>> and do the socket-accept.
>I know you can use select() or poll() to block until an accept() would
>succeed, is that the idea?
  Yes.  Have the server task poll (frequently) to see if an accept() would
succeed, then rendezvous with the handler task which does the actual
accept().  Note the OP's Get_Line could take a very long time if the
caller is not a fast browser - a typist surfing with telnet www.x 80, say.
So having the server do the Get_Line allows such a single slow typist to
block all other new traffic.
  In this case, though, the server could start/call a task and not worry
about whether the task blocks on the accept().  If it does block, then
there's no browser calling and the server has nothing else to do anyway.
Eventually somebody surfs by, at which time the task hanging on the
accept() does the accept() and immediately finishes its rendezvous and the
server is allowed to go and prepare another acceptor task.
  The server is like a restaurant maitre d' - he should be minimizing
the time people wait at the door.  To do that he assigns them to a
waiter, who takes their drink order, tells them the daily specials, etc.
while the maitre d' turns his attention to the next customer in line.
  One more thing: if the server does the Get_Line, that suggests there's
only one Get_Line per accept(), ie, no persistent connections.



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: copy constructor for sockets
  2004-05-24  5:20           ` tmoran
@ 2004-05-25  4:53             ` Simon Wright
  0 siblings, 0 replies; 21+ messages in thread
From: Simon Wright @ 2004-05-25  4:53 UTC (permalink / raw)


tmoran@acm.org writes:

> >I have it stuck in my head that Finalize can get called more than
> >once. Which would make a mockery of (simple-minded) reference counting
>   If each copy of the socket points to the single shared ref count
> (Rep_Type here), then Finalize may be called as often as you want on the
> socket:  the first time it's called it decrements the shared reference
> count, frees the Rep_Type if the count is now zero, and nulls the socket's
> pointer.  Subsequent calls on the same socket see that the pointer is null
> and there's nothing to do.

Of course, thanks Tom & Matt!



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: copy constructor for sockets
  2004-05-24 18:26     ` tmoran
@ 2004-05-25  5:10       ` Simon Wright
  2004-05-25  6:37         ` tmoran
  0 siblings, 1 reply; 21+ messages in thread
From: Simon Wright @ 2004-05-25  5:10 UTC (permalink / raw)


tmoran@acm.org writes:

> >> socket to the task during the rendezvous, and let the task create
> >> a socket and do the socket-accept.

> >I know you can use select() or poll() to block until an accept()
> >would succeed, is that the idea?

>   Yes.  Have the server task poll (frequently) to see if an accept()
> would succeed, then rendezvous with the handler task which does the
> actual accept().

I was thinking of poll(2), which can be told to block indefinitely
until some event occurs: 'man 2 poll' says

       poll is a variation on the theme of select.  It  specifies
       an array of nfds structures of type
               struct pollfd {
                       int fd;           /* file descriptor */
                       short events;     /* requested events */
                       short revents;    /* returned events */
               };
       and  a  timeout  in  milliseconds.  A negative value means
       infinite timeout.  The field fd contains a file descriptor
       for an open file.

       (etc)

>   In this case, though, the server could start/call a task and not
> worry about whether the task blocks on the accept().  If it does
> block, then there's no browser calling and the server has nothing
> else to do anyway.  Eventually somebody surfs by, at which time the
> task hanging on the accept() does the accept() and immediately
> finishes its rendezvous and the server is allowed to go and prepare
> another acceptor task.

I think there could be a problem with this if there's some problem
such that the accept(2) fails immediately, I suppose you could raise
an exception in the rendezvous if so,

>   One more thing: if the server does the Get_Line, that suggests
> there's only one Get_Line per accept(), ie, no persistent
> connections.

I don't see that, so long as the server hands on the connected socket?

-- 
Simon Wright                               100% Ada, no bugs.



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: copy constructor for sockets
  2004-05-24 11:28 copy constructor for sockets Andrew Carroll
@ 2004-05-25  5:29 ` Simon Wright
  0 siblings, 0 replies; 21+ messages in thread
From: Simon Wright @ 2004-05-25  5:29 UTC (permalink / raw)


"Andrew Carroll" <andrew@carroll-tech.net> writes:

> All the "accepting" task does is initialize sockets and create new
> tasks.  Well, it will do other things but right now I am just
> experimenting.  Your select() or poll() idea is beautiful!  Because
> then, when an accept would occur, I can have the tasks ('A' or 'B')
> handle the whole "session".  Question now is, how do I know which
> task to assign it to for handling?  I cannot get into the HTTP
> header before I "accept".  Hmmmm....Anyway...

I think that's a big Hmmmm :-(

The task is a thread of control, whereas you want different
behaviour. When I was designing my Embedded Web Server
(http://sourceforge.net/projects/embed-web-srvr/) I managed that by
having the Response be a tagged type, created by factory operations
registered against the .. damn, forgotten the name, the
"/projects/embed-web-srvr/" in the URL above.

> Never the less I am learning some great things.  You mentioned that
> a socket is a file descriptor (Unix) and I'm not quite sure I fully
> understand the implications of that.  I "heard" that sockets were
> designed in such a way that it would be "transparent", like working
> with files.  Does that mean I can do a seek() on a socket?  When
> people throw out the term "file descriptor" and start talking about
> "small positive integers" I draw a blank as to how those are used
> for "communication" over a network device in general.  After all,
> there are MANY small positive integers on my computer.  I'm assuming
> the file descriptor (fd) means something to the OS?  So somewhere in
> the kernel or "shell" interrupt handler there is an else if (//it is
> a small positive integer) { //must be a socket, fire-up the RS-232
> driver}?

It's going to be some higher level of abstraction in the OS than that,
after all you might be using an Ethernet LAN or a cable modem. But,
yes-ish.

> I thought a socket was an abstraction from an address?  For
> example. the address to a UART or RS-232 PIC.  A driver of which is
> written (probably a module) to control that device.  So how does a
> fd relate to that driver?  Or are you saying that somewhere in my
> /dev directory there is a directory entry for my UART?  I can just
> arbitrarily (at risk of destruction) send data to the UART through
> an entry in the /dev directory?

_Very_ roughly, on Unix (POSIX) systems, the fd looks to you, the
user, as a small positive integer, but inside the OS it's an index
into a whole set of data structures. These might hold pointers to the
actual operations to perform read(), write(), sendTo() etc + pointers
to the actual connected channel (console i/o for fd 0, some networking
stack for your server).

But you're right, it is an abstraction; this small positive integer is
not something you want to go adding 1 to!

-- 
Simon Wright                               100% Ada, no bugs.



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: copy constructor for sockets
  2004-05-25  5:10       ` Simon Wright
@ 2004-05-25  6:37         ` tmoran
  0 siblings, 0 replies; 21+ messages in thread
From: tmoran @ 2004-05-25  6:37 UTC (permalink / raw)


>>   One more thing: if the server does the Get_Line, that suggests
>> there's only one Get_Line per accept(), ie, no persistent
>> connections.
>
>I don't see that, so long as the server hands on the connected socket?
  When a Get_Handler task is done with the Get, does it do a Get_Line
to see if the socket is persistent, and if so, what is the next request?
  If the server does the Get_Line that determines whether the next request
is a Get or a Post, how does it handle the next request on a persistent
connection?  The server must be coded to wait, not simply for an accept()
to unblock, but for either an accept() unblock OR a worker task finishing
and handing back the (still potentially live) socket.



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: copy constructor for sockets
  2004-05-24  4:53         ` Simon Wright
  2004-05-24  5:20           ` tmoran
  2004-05-24 12:36           ` Matthew Heaney
@ 2004-05-25 21:50           ` Robert I. Eachus
  2 siblings, 0 replies; 21+ messages in thread
From: Robert I. Eachus @ 2004-05-25 21:50 UTC (permalink / raw)


Simon Wright wrote:

> Matthew Heaney <matthewjheaney@earthlink.net> writes:
> 
> 
>>>in which of these times you should decrement,
>>
>>Huh?  Every time, of course.  How could it be otherwise?  What would
>>a reference counting scheme even mean, if you didn't decrement the
>>refcount during finalization of the object?
> 
> I have it stuck in my head that Finalize can get called more than
> once. Which would make a mockery of (simple-minded) reference counting
> schemes, of course. Please tell me it ain't so! (or explain why it's
> not actually a problem ..)

Yes, Finalize can be called more than once, especially when exceptions 
occur.  The solution I usually use is to something else during the 
finalization, and only change the reference count if that succeeds.  In 
a reference counting scheme you need a "finalized" flag as well as an 
initialized flag, which can be different values in the same byte 
(uninitialized, valid, finalized).


-- 

                                           Robert I. Eachus

"The terrorists rejoice in the killing of the innocent, and have 
promised similar violence against Americans, against all free peoples, 
and against any Muslims who reject their ideology of murder. Their 
barbarism cannot be appeased, and their hatred cannot be satisfied. 
There's only one way to deal with terror: We must confront the enemy and 
stay on the offensive until these killers are defeated." -- George W. Bush




^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2004-05-25 21:50 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-05-24 11:28 copy constructor for sockets Andrew Carroll
2004-05-25  5:29 ` Simon Wright
  -- strict thread matches above, loose matches on Subject: below --
2004-05-22 21:18 Andrew Carroll
2004-05-22 21:46 ` tmoran
2004-05-23 11:21   ` Simon Wright
2004-05-24 18:26     ` tmoran
2004-05-25  5:10       ` Simon Wright
2004-05-25  6:37         ` tmoran
2004-05-23  9:43 ` Mark Lorenzen
2004-05-23 11:27 ` Simon Wright
2004-05-22 10:19 Andrew Carroll
2004-05-22 11:55 ` Simon Wright
2004-05-22 18:39   ` tmoran
2004-05-23 21:04   ` Matthew Heaney
2004-05-24  7:13     ` Marius Amado Alves
2004-05-24  3:23       ` Matthew Heaney
2004-05-24  4:53         ` Simon Wright
2004-05-24  5:20           ` tmoran
2004-05-25  4:53             ` Simon Wright
2004-05-24 12:36           ` Matthew Heaney
2004-05-25 21:50           ` Robert I. Eachus

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox