module: access-path-implementation synopsis: Modelling remote objects author: Paul Howard Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND ///// define abstract class () slot nub-descriptor :: ; slot access-path :: ; // other slots? end class; ///// define abstract class () slot nub-descriptor :: , required-init-keyword: nub-descriptor:; slot access-path :: ; slot thread-name :: , init-keyword: name:; slot thread-state :: , init-keyword: state:, init-value: "[Can't get thread state]"; slot os-thread-priority :: , init-keyword: os-priority:; slot stack :: false-or(), init-value: #f; slot thread-suspended? :: , init-value: #f; end class; define variable *next-thread-id* :: = 0; define class () end class; define method make (class == , #rest keys, #key, #all-keys) apply (make, , keys); end method; ///// define abstract class () slot nub-descriptor :: , init-keyword: nub-descriptor:; slot access-path :: ; slot library-version :: , init-keyword: version:, init-value: "Version Unknown"; slot library-image-name :: , init-keyword: locator:; slot library-core-name :: , init-value: "pants"; slot static-symbols :: , init-value: #[]; slot exported-symbols :: , init-value: #[]; slot global-symbols :: , init-value: #[]; end class; define class () end class; define method make (class == , #rest keys, #key, #all-keys) apply (make, , keys); end method; define variable *the-only-library* = make (, nub-descriptor: 0, version: "Version Unknown", locator: "pants.exe"); ///// LOCAL FUNCTIONS. define generic connection-all-threads (conn :: ) => (_ :: ); define generic connection-all-libraries (conn :: ) => (_ :: ); define generic application-all-threads (ap :: ) => (_ :: ); define generic update-access-path-libraries (ap :: ) => (); ///// GENERIC FUNCTIONS define generic host-machine () => (_ :: ); define generic do-processes (function :: , dc :: ) => (); define generic do-threads (function :: , ap :: ) => (); define generic do-libraries (function :: , ap :: ) => (); define generic thread-priority (t :: , #key normalize? = #t) => (_ :: ); ///// HOST-MACHINE (is just a hack for now) define method host-machine () => (_ :: ); *default-local-debugger-connection*; end method; ///// DO-PROCESSES (is just a hack for now) define method do-processes (function :: , dc :: ) => () end method; ///// DEBUGGABLE? // Just a hack for now... define method debuggable? (p :: ) => (_ :: ) #f end method; ///// THREAD-PRIORITY define method thread-priority (t :: , #key normalize? = #t) => (_ :: ) t.os-thread-priority; end method; ///// DO-THREADS define method do-threads (function :: , ap :: ) => () // Iterate over the vector with the supplied function. for (this-thread in ap.threads) function(this-thread) end for; end method; ///// DO-LIBRARIES define method do-libraries (function :: , ap :: ) => () function (*the-only-library*); end method; ///// CONSTRUCT-THREAD-OBJECT // Given a low-level thread descriptor (a ), use it to pull // across all thread information from the debugger nub and construct // a high-level object. define method construct-thread-object (conn :: , thread :: ) => (_ :: ) let thread-name = format-to-string ("DBGTHREAD%d", *next-thread-id*); let priority :: = 0; *next-thread-id* := *next-thread-id* + 1; make (, name: thread-name, os-priority: priority, nub-descriptor: thread); end method; ///// FIND-OR-MAKE-THREAD // The access path maintains a list of active threads. This list is // extended as new threads are created, and shortened when threads are // destroyed. (Stop-reason information is used to do this). Every thread // in the list has a unique nub-descriptor (a ). This function // searches the current state of the list and looks for a thread with the // given descriptor. If it is found, it is returned. Otherwise, a new // thread is added to the list and returned. define method find-or-make-thread (ap :: , thread :: ) => (_ :: ) let i = 0; let remote-thread = #f; while ((~remote-thread) & (i < size(ap.threads))) if (ap.threads[i].nub-descriptor == thread) remote-thread := ap.threads[i]; else i := i + 1; end if end while; if (~remote-thread) remote-thread := construct-thread-object (ap.connection, thread); ap.threads := add! (ap.threads, remote-thread); end if; remote-thread; end method; ///// CONSTRUCT-LIBRARY-OBJECT // Similar to CONSTRUCT-THREAD-OBJECT. define method construct-library-object (conn :: , lib :: ) => (_ :: ) make (, nub-descriptor: 0, locator: "pants.exe"); end method; ///// FIND-OR-MAKE-LIBRARY // Similar to FIND-OR-MAKE-THREAD define method find-or-make-library (ap :: , lib :: ) => (_ :: ) let i = 0; let remote-library = #f; while ((~remote-library) & (i < size(ap.libraries))) if (ap.libraries[i].nub-descriptor = lib) remote-library := ap.libraries[i]; else i := i + 1; end if end while; if (~remote-library) remote-library := construct-library-object (ap.connection, lib); ap.libraries := add! (ap.libraries, remote-library); end if; remote-library; end method; ///// SUSPEND-ALL-EXCEPT // A useful function for suspending all threads in the application // except for one. define method suspend-all-except (ap :: , thr :: ) => () do-threads (ap, method (t :: ) unless (t == thr) suspend-thread (ap, t) end unless end method); end method; ///// RESUME-ALL-EXCEPT // Undoes the work of suspend-all-except define method resume-all-except (ap :: , thr :: ) => () do-threads (ap, method (t :: ) unless (t == thr) resume-thread (ap, t) end unless end method); end method;