home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #20 / NN_1992_20.iso / spool / comp / sys / next / programm / 6047 < prev    next >
Encoding:
Text File  |  1992-09-08  |  10.5 KB  |  398 lines

  1. Path: sparky!uunet!overload!dillon
  2. From: dillon@overload.Berkeley.CA.US (Matthew Dillon)
  3. Newsgroups: comp.sys.next.programmer
  4. Subject: NS3.0 Distributed objects questions / example code
  5. Distribution: world
  6. Message-ID: <dillon.0nd9@overload.Berkeley.CA.US>
  7. Date: 7 Sep 92 14:25:26 PST
  8. Organization: Not an Organization
  9. Lines: 387
  10.  
  11.     This documentation is *AWEFUL*!!  You get little one paragraph
  12.     descriptions that tell you very little about how things are supposed to
  13.     work.  There were only 3 examples in the NeXT supplied documentation
  14.     for distributed objects and the one I was interested in --
  15.     multi-threading on the server side, is broken (it leaves threads lying
  16.     around after the client exits).
  17.  
  18.     If anyone has any idea re: the following I would greatly appreciate an
  19.     answer.  Please post answers to the net!
  20.  
  21.     Goal:
  22.  
  23.     I have a server process which registers a named
  24.     NXConnection.  I have N client processes which wish
  25.     to connect to this server process.
  26.  
  27.     I want the server to SILENTLY fork off a thread for each client
  28.     that connects to it.
  29.  
  30.     Problems:
  31.  
  32.     Currently this does not seem possible without writing a bandaid
  33.     called 'newThread' which the client must then call.  Unfortunately,
  34.     this bandaid not only requires the client to KNOW that the server
  35.     is doing something wierd (it should be invisible), but also causes
  36.     the server to call its - connection method whenever any method is
  37.     called using the original proxy.
  38.  
  39.     (1) The - connection method is described in all of one paragraph
  40.         in the NeXT documentation.    It does not give you any hint
  41.         on how the arguments are supposed to be used and how the
  42.         returned connection is interpreted.
  43.  
  44.         In example program #1 below the - connection method is called
  45.         just once for each client no matter how many operations that
  46.         client performs on its proxy.  This works as expected
  47.  
  48.     (2) Normally the inPort for a new connection <newConn> is the same
  49.         as the inPort for the registration <conn>, meaning that you
  50.         cannot fork off a thread to handle that connection because all
  51.         the threads will try to read data from the same port.  That
  52.         is, you want a particular thread to process a particular
  53.         connection and no other.
  54.  
  55.         So, in example #2 I tried to use connectToPort:withInPort: to
  56.         setup a separate inPort for the connection then run said
  57.         connection in a new thread.  Unfortunately, this didn't work
  58.         big time:
  59.  
  60.         (a) The - connection method on the server is run EACH TIME
  61.         the client calls a method in its original proxy object (it
  62.         didn't do this in example #1!!).  This appears to be due to my
  63.         returning something other then <conn> in the - connection
  64.         method.
  65.  
  66.         (b) Further, the client's proxy does not appear to access the
  67.         new port.
  68.  
  69.         (c) If the client then calls the - newThread method it
  70.         obtains a new proxy object which DOES appear to use the
  71.         proper connection (the one that I tried to setup and fork
  72.         off to a separate thread).    This is the bandaid, but has
  73.         bad side effects as I described above.
  74.  
  75.     (3) registerForInvalidationNotification does not appear to work
  76.         at all.  It does not work with the NeXT provided examples.
  77.         When a client exits the server is never notified and the now
  78.         defunct thread sticks around. (example program #2)
  79.  
  80.         use 'ps m' to list the threads
  81.  
  82.     I don't want alienate NeXT but I gotta say that you guys (NeXT people)
  83.     MUST provide more SELF CONTAINED (i.e. compilable) examples to
  84.     demonstrate all the quirks your documentation doesn't talk about.  It
  85.     took me ALL DAY to just get as far as I did and half of what I learned
  86.     isn't covered in any documentation anywhere.  The only thing of any use
  87.     are the few examples in Examples/ ... most of the examples embedded in
  88.     the documentation are totally useless because they assume you
  89.     understand the 10,000 items that had to be setup before the particular
  90.     lines shown in the example.  That's no example!
  91.  
  92.     Any Netter's out there who've figured this out would have my undying
  93.     thanks if they posted the solution to the net!
  94.  
  95.                     Thanks,
  96.  
  97.                     -Matt
  98.  
  99. ------------------------------- CUT HERE ---------------------------
  100.  
  101.  
  102. /*
  103.  *  MTHREAD1.C
  104.  *
  105.  *  Modified from developer examples
  106.  *
  107.  *  A simple multi-threaded example
  108.  */
  109.  
  110. #import <objc/Object.h>
  111. #import <remote/NXConnection.h>
  112. #import <remote/NXProxy.h>
  113. #import <mach/cthreads.h>
  114. #import <machkit/NXPort.h>
  115. #import <machkit/senderIsInvalid.h>
  116.  
  117. /*
  118.  *  Our protocol
  119.  */
  120.  
  121. @protocol ServerProtocol
  122. - newThread;
  123. - (int) doWork;
  124. @end
  125.  
  126. /*
  127.  *  Our object class which uses the protocol
  128.  */
  129.  
  130. @interface MTS : Object <ServerProtocol, NXSenderIsInvalid>
  131. @end
  132.  
  133. /*
  134.  *  Our implementation
  135.  */
  136.  
  137. @implementation MTS
  138.  
  139. /*
  140.  *  Method called when a client connects to us.  connect provides us
  141.  *  with <conn>, a connection which shares topConn's input port and
  142.  *  has its own output port.  The associated object is <self> (i.e. the
  143.  *  one we registered with the name sever)
  144.  *
  145.  *  connection in this case is only called once
  146.  */
  147.  
  148. - connection: (NXConnection *)topConn didConnect:(NXConnection *)conn {
  149.     printf("connect\n");
  150.     [conn registerForInvalidationNotification:self];
  151.     return(conn);
  152. }
  153.  
  154. - senderIsInvalid: sender
  155. {
  156.     puts("died!");
  157. }
  158.  
  159. - newThread {
  160.     puts("new thread");
  161.     return self;
  162. }
  163.  
  164. - (int) doWork {
  165.     puts("do work");
  166.     return (int) cthread_self();
  167. }
  168.  
  169. @end
  170.  
  171. /*
  172.  *  Run the program twice... the first process will be the server, the second
  173.  *  will be the client (the third will be a client, etc...)
  174.  */
  175.  
  176. main()
  177. {
  178.     id hub;    // proxy object (client) or server object
  179.  
  180.     hub = [NXConnection connectToName:"MTS example"];
  181.  
  182.     printf("I am %d\n", cthread_self());
  183.  
  184.     objc_setMultithreaded(YES);
  185.  
  186.     if (hub) {
  187.     id core;    // object to handle invalidation notification
  188.     id sub;
  189.     short i;
  190.  
  191.     /*
  192.      *  We are a client, <hub> is our proxy.  Create <core> to handle
  193.      *  invalidation notifcation since we can't use <hub>
  194.      */
  195.  
  196.     core = [[MTS alloc] init];
  197.     [[hub connectionForProxy] registerForInvalidationNotification:core];
  198.     [hub setProtocolForProxy:@protocol(ServerProtocol)];
  199.  
  200.     puts("client connect");
  201.  
  202.     printf("dowork is %d\n", [hub doWork]);
  203.     printf("dowork is %d\n", [hub doWork]);
  204.     printf("dowork is %d\n", [hub doWork]);
  205.     printf("newThread is %08lx\n", [hub newThread]);
  206.     printf("newThread is %08lx\n", [hub newThread]);
  207.     printf("newThread is %08lx\n", [hub newThread]);
  208.     } else {
  209.     id topConn;            // our server connection
  210.  
  211.     /*
  212.      *  Make us a server, create hub and register for invalidation
  213.      *  notification
  214.      */
  215.  
  216.     hub = [MTS new];
  217.     printf("self is %08lx\n", hub);
  218.     topConn = [NXConnection registerRoot:hub withName:"MTS example"];
  219.     [topConn registerForInvalidationNotification:hub];
  220.     puts("server wait");
  221.     [topConn setDelegate:hub];        // so hub gets connection msg
  222.     [topConn run];
  223.     }
  224.     return(0);
  225. }
  226.  
  227. ------------------------------- CUT HERE ---------------------------
  228.  
  229.  
  230. /*
  231.  *  MTHREAD2.C
  232.  *
  233.  *  Modified from developer examples
  234.  *
  235.  *  A simple multi-threaded example, Each new client gets a dedicated
  236.  *  thread.
  237.  */
  238.  
  239. #import <objc/Object.h>
  240. #import <remote/NXConnection.h>
  241. #import <remote/NXProxy.h>
  242. #import <mach/cthreads.h>
  243. #import <machkit/NXPort.h>
  244. #import <machkit/senderIsInvalid.h>
  245.  
  246. /*
  247.  *  Our protocol
  248.  */
  249.  
  250. @protocol ServerProtocol
  251. - newThread;
  252. - (int) doWork;
  253. @end
  254.  
  255. /*
  256.  *  Our object class which uses the protocol
  257.  */
  258.  
  259. @interface MTS : Object <ServerProtocol, NXSenderIsInvalid>
  260. @end
  261.  
  262. /*
  263.  *  Our implementation
  264.  */
  265.  
  266. @implementation MTS
  267.  
  268. /*
  269.  *  Connections are handled by the main thread only.  Note that the
  270.  *  inPort for the proxy object obtained by the client works under
  271.  *  the 'third party server' paradigm, meaning that each accesses to
  272.  *  it is a connection.  This occurs even if the 'server' is the same
  273.  *  machine as the program which posted the named port.
  274.  *
  275.  *  topConn is the server place holder, conn is an instance connection.  Note
  276.  *  that conn may/will have the same inPort as topConn.  Therefore, we cannot
  277.  *  simply [conn runInNewThread] because it will compete with the main
  278.  *  thread for data.
  279.  */
  280.  
  281. - connection: (NXConnection *)topConn didConnect:(NXConnection *)conn {
  282.     id threadConn;
  283.     id proxy;
  284.     id inPort = [NXPort new];
  285.     id mts = [MTS new];
  286.  
  287.     puts("connect");
  288.     proxy = [NXConnection connectToPort:[conn outPort] withInPort:inPort];
  289.     threadConn = [proxy connectionForProxy];
  290.     [conn free];
  291.     [threadConn registerForInvalidationNotification:mts];
  292.     [threadConn runInNewThread];
  293.     [threadConn setRoot:mts];
  294.  
  295.     return (threadConn);
  296. }
  297.  
  298. - senderIsInvalid: sender
  299. {
  300.     printf("Sender %08lx died!\n", sender);
  301.     write(1, "XXX\n", 4);
  302. }
  303.  
  304. /*
  305.  *
  306.  */
  307.  
  308. - newThread {
  309.     printf("New Thread %08lx %d\n", self, cthread_self());
  310.     return self;
  311. }
  312.  
  313. - (int) doWork {
  314.     printf("DoWork: %08lx %d\n", self, cthread_self());
  315.     return (int) cthread_self();
  316. }
  317.  
  318. @end
  319.  
  320. /*
  321.  *  Run the program twice... the first process will be the server, the second
  322.  *  will be a client.
  323.  */
  324.  
  325. main()
  326. {
  327.     id hub;    // proxy object (client) or server object
  328.  
  329.     hub = [NXConnection connectToName:"MTS example"];
  330.  
  331.     printf("I am %d\n", cthread_self());
  332.  
  333.     objc_setMultithreaded(YES);
  334.  
  335.     if (hub) {
  336.     id core;    // object to handle invalidation notification
  337.     id sub;
  338.     short i;
  339.  
  340.     /*
  341.      *  We are a client, <hub> is our proxy.  Create <core> to handle
  342.      *  invalidation notifcation since we can't use <hub>
  343.      */
  344.     core = [[MTS alloc] init];
  345.     [[hub connectionForProxy] registerForInvalidationNotification:core];
  346.     [hub setProtocolForProxy:@protocol(ServerProtocol)];
  347.  
  348.     puts("client connect");
  349.  
  350.     for (i = 0; i < 5; ++i) {
  351.         sleep(1);
  352.         printf("test-doWork %d\n", [hub doWork]);
  353.     }
  354.  
  355.     sub = [hub newThread];
  356.     for (i = 0; i < 5; ++i) {
  357.         sleep(1);
  358.         printf("sub %d: %d\n", i, [sub doWork]);
  359.     }
  360.     for (i = 0; i < 5; ++i) {
  361.         sleep(1);
  362.         printf("test-doWork %d\n", [hub doWork]);
  363.     }
  364.     sub = [hub newThread];
  365.     for (i = 0; i < 5; ++i) {
  366.         sleep(1);
  367.         printf("sub %d: %d\n", i, [sub doWork]);
  368.     }
  369.     } else {
  370.     id topConn;            // our server connection
  371.  
  372.     /*
  373.      *  Make us a server, create hub and register for invalidation
  374.      *  notification
  375.      */
  376.  
  377.     hub = [MTS new];
  378.     printf("self is %08lx\n", hub);
  379.     topConn = [NXConnection registerRoot:hub withName:"MTS example"];
  380.     [topConn registerForInvalidationNotification:hub];
  381.     puts("server wait");
  382.     [topConn setDelegate:hub];        // so hub gets connection msg
  383.     [topConn run];
  384.     }
  385.     return(0);
  386. }
  387.  
  388. ------------------------------- CUT HERE ---------------------------
  389.  
  390.  
  391. --
  392.  
  393.     Matthew Dillon        dillon@Overload.Berkeley.CA.US
  394.     891 Regal Rd.        uunet.uu.net!overload!dillon
  395.     Berkeley, Ca. 94708     ham: KC6LVW (no mail drop)
  396.     USA             Sandel-Avery Engineering (702)831-8000
  397.  
  398.