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 () constant slot nub-descriptor :: , init-keyword: nub-descriptor:; constant slot remote-process-name :: , init-value: "{anonymous process}", init-keyword: remote-process-name:; constant slot remote-process-system-identifier :: , init-value: "0", init-keyword: remote-process-system-identifier:; constant slot remote-process-actual-identifier :: , init-keyword: remote-process-actual-identifier:; end class; define class () end class; define method make (class == , #rest keys, #key, #all-keys) => (proc) apply (make, , keys); end method; ///// define abstract class () constant slot nub-descriptor :: , required-init-keyword: nub-descriptor:; constant slot rnub-descriptor :: , required-init-keyword: rnub-descriptor:; constant slot thread-access-path :: , required-init-keyword: access-path:; constant slot thread-name :: , init-keyword: name:; slot thread-state :: , init-keyword: state:, init-value: "[Can't get thread state]"; constant slot os-thread-priority :: , init-keyword: os-priority:; slot thread-stack :: false-or(), init-value: #f; slot thread-suspended? :: , init-value: #f; slot stack-size-valid? :: , init-value: #f; slot stack-size :: , init-value: 0; slot stack-trace-valid? :: , init-value: #f; slot source-stepping-control-applied? :: , init-value: #f; end class; define variable *next-thread-id* :: = 0; define class () end class; define method make (class == , #rest keys, #key, #all-keys) => (thread) apply (make, , keys); end method; define method print-object (t :: , stream :: ) => () format(stream, "{Remote Thread [%=, %=, %=, %=, %=, %=]}", t.thread-name, t.nub-descriptor, t.thread-state, t.os-thread-priority, t.thread-stack, t.thread-suspended?); end; ///// define abstract class () constant slot nub-descriptor :: , init-keyword: nub-descriptor:; constant slot rnub-descriptor :: , init-keyword: rnub-descriptor:; constant slot library-version-major :: , init-keyword: version-major:, init-value: 0; constant slot library-version-minor :: , init-keyword: version-minor:, init-value: 0; constant slot library-image-name :: , init-keyword: locator:; constant slot library-core-name :: , init-keyword: core-name:, init-value: "unknown"; constant slot library-base-address :: , init-keyword: base-address:, init-value: as-remote-value(0); constant slot library-object-files :: = make(); slot self-contained-component? :: = #f; /* slot static-symbols :: , init-value: #[]; slot exported-symbols :: , init-value: #[]; slot global-symbols :: , init-value: #[]; */ end class; define generic library-version (lib :: ) => (major-version-number :: , minor-version-number :: ); define class () end class; define method make (class == , #rest keys, #key, #all-keys) => (lbry) apply (make, , keys); end method; define method library-version (lib :: ) => (major-version-number :: , minor-version-number :: ) values(lib.library-version-major, lib.library-version-minor) end method; ///// GENERIC FUNCTIONS define open 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) => (p :: ); ///// DO-PROCESSES define method do-processes (function :: , dc :: ) => () local method find-existing (descr :: ) => (p? :: false-or()) block (return) for (proc in dc.connection-process-list) if (proc.nub-descriptor = descr) return(proc) end if; end for; return(#f); end block; end method; let proc-count = update-local-process-list(); let new-list = make(, size: 0); for (i from 0 below proc-count) let descr = local-process-nub-descriptor(i); add!(new-list, find-existing(descr) | begin let nl = local-process-name-length(i); let sys-idl = local-process-system-identifier-length(i); let nm = make(, size: nl); let sys-id = make(, size: sys-idl); local-process-name(i, nl, nm); local-process-system-identifier(i, sys-idl, sys-id); make(, nub-descriptor: descr, remote-process-name: nm, remote-process-system-identifier: sys-id) end) end for; dc.connection-process-list := new-list; for (proc in new-list) function(proc) end for; values() end method; ///// GET-PROCESS-PAGE-FAULT-COUNT define method get-process-page-fault-count (ap :: ) => (count :: ) get-process-page-fault-count-on-connection(ap.connection); end method; define open generic get-process-page-fault-count-on-connection (conn :: ) => (count :: ); define method get-process-page-fault-count-on-connection (conn :: ) => (count :: ) nub-get-process-page-fault-count(conn.connection-process); end method; ///// THREAD-PRIORITY define method thread-priority (t :: , #key normalize? = #t) => (p :: ) 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; ///// NUMBER-OF-ACTIVE-THREADS define method number-of-active-threads (ap :: ) => (count :: ) size(ap.threads) end method; ///// GET-THREAD-CPU-TIME define method get-thread-cpu-time (ap :: , thread :: ) => (timer :: ) get-thread-cpu-time-on-connection(ap.connection, thread); end method; define open generic get-thread-cpu-time-on-connection (conn :: , thread :: ) => (timer :: ); define method get-thread-cpu-time-on-connection (conn :: , thread :: ) => (timer :: ) nub-get-thread-cpu-time(conn.connection-process, thread.nub-descriptor); end method; ///// DO-LIBRARIES define method do-libraries (function :: , ap :: ) => () for (this-library in ap.libraries) function (this-library); end for; 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 open generic construct-thread-object (conn :: , thread :: , #key) => (thread :: ); define method construct-thread-object (conn :: , thread :: , #key path, priority) => (thread :: ) let thread-name = format-to-string ("DBGTHREAD%d", *next-thread-id*); let priority :: = priority | nub-thread-os-priority (conn.connection-process, thread); *next-thread-id* := *next-thread-id* + 1; make (, name: thread-name, access-path: path, os-priority: priority, nub-descriptor: thread, rnub-descriptor: as-integer(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 :: , #key priority) => (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, path: ap, priority: priority); ap.threads := add! (ap.threads, remote-thread); end if; remote-thread; end method; ///// CONSTRUCT-LIBRARY-OBJECT // Similar to CONSTRUCT-THREAD-OBJECT. define open generic construct-library-object (conn :: , lib :: ) => (lib :: ); define method construct-library-object (conn :: , lib :: ) => (lib :: ) let name-length :: = nub-get-library-filename-length (conn.connection-process, lib); let C-filename = make (, size: name-length); let basic-name-length = nub-get-library-undecorated-name-length(conn.connection-process, lib); let basic-name = make(, size: basic-name-length); let (major-v, minor-v) = nub-get-library-version(conn.connection-process, lib); let base-addr = nub-get-library-base-address(conn.connection-process, lib); nub-get-library-filename (conn.connection-process, lib, name-length, C-filename); nub-get-library-undecorated-name(conn.connection-process, lib, name-length, basic-name); make (, nub-descriptor: lib, locator: as-uppercase(C-filename), core-name: as-uppercase(basic-name), version-major: major-v, version-minor: minor-v, base-address: base-addr); end method; ///// FIND-OR-MAKE-LIBRARY // Similar to FIND-OR-MAKE-THREAD define method find-or-make-library (ap :: , lib :: ) => (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 (method (t :: ) unless (t == thr) suspend-thread (ap, t) end unless end method, ap); end method; ///// RESUME-ALL-EXCEPT // Undoes the work of suspend-all-except define method resume-all-except (ap :: , thr :: ) => () do-threads (method (t :: ) unless (t == thr) resume-thread (ap, t) end unless end method, ap); end method; */