EA200601942A1 20070427 Номер и дата охранного документа [PDF] EAPO2007\TIT_PDF/200601942 Титульный лист описания [PDF] EAPO2007/PDF/200601942 Полный текст описания EA200601942 20050422 Регистрационный номер и дата заявки AU2004902146 20040422 Регистрационные номера и даты приоритетных заявок AU2005/000580 Номер международной заявки (PCT) WO2005/103926 20051103 Номер публикации международной заявки (PCT) EAA1 Код вида документа [eaa] EAA20702 Номер бюллетеня [RU] МОДИФИЦИРОВАННАЯ КОМПЬЮТЕРНАЯ АРХИТЕКТУРА С СОГЛАСОВАННЫМИ ОБЪЕКТАМИ Название документа G06F 15/16 Индексы МПК [AU] Холт Джон Матью Сведения об авторах [AU] ВОРЭТЕК ПТИ ЛИМИТЕД Сведения о заявителях
 

Патентная документация ЕАПВ

 
Запрос:  ea200601942a*\id

больше ...

Термины запроса в документе

Реферат

Настоящее изобретение раскрывает модифицированную компьютерную архитектуру (50, 71, 72), которая позволяет программе (50) приложения выполняться одновременно на множестве компьютеров (M1, ...Mn). Совместно используемая память на каждом компьютере обновляется при внесении изменений и/или при перезаписи, так что все запросы на считывание памяти удовлетворяются локально. Во время первоначальной загрузки (75) программы, или аналогичной процедуры, происходит идентификация (92) команд, которые приводят к перезаписи или видоизменению памяти. Вставляются (103) дополнительные команды для обновления эквивалентных адресов памяти на всех компьютерах. Кроме этого, раскрыта инициализация классов и объектов языка JAVA (162, 163), так что все адреса памяти для всех компьютеров инициализируются аналогичным образом. Также раскрыта финализация объектов и классов языка JAVA (162, 163), так что финализация происходит только тогда, когда последний класс или объект, присутствующий на всех машинах, более не нужен. Во время начальной загрузки (75) программы, или аналогичной процедуры, производится идентификация команд, которые приводят к получению (или освобождению) программой приложения блокиратора для конкретного ресурса (50A, 50X-50Y) (синхронизация). Вставляются (162, 163) дополнительные команды для того, чтобы модифицировать подпрограмму синхронизации, которая обновляет все компьютеры.

 


Полный текст патента

(57) Реферат / Формула:
изобретение раскрывает модифицированную компьютерную архитектуру (50, 71, 72), которая позволяет программе (50) приложения выполняться одновременно на множестве компьютеров (M1, ...Mn). Совместно используемая память на каждом компьютере обновляется при внесении изменений и/или при перезаписи, так что все запросы на считывание памяти удовлетворяются локально. Во время первоначальной загрузки (75) программы, или аналогичной процедуры, происходит идентификация (92) команд, которые приводят к перезаписи или видоизменению памяти. Вставляются (103) дополнительные команды для обновления эквивалентных адресов памяти на всех компьютерах. Кроме этого, раскрыта инициализация классов и объектов языка JAVA (162, 163), так что все адреса памяти для всех компьютеров инициализируются аналогичным образом. Также раскрыта финализация объектов и классов языка JAVA (162, 163), так что финализация происходит только тогда, когда последний класс или объект, присутствующий на всех машинах, более не нужен. Во время начальной загрузки (75) программы, или аналогичной процедуры, производится идентификация команд, которые приводят к получению (или освобождению) программой приложения блокиратора для конкретного ресурса (50A, 50X-50Y) (синхронизация). Вставляются (162, 163) дополнительные команды для того, чтобы модифицировать подпрограмму синхронизации, которая обновляет все компьютеры.

 


WO 2005/103926
PCT/AU2005/000580
МОДИФИЦИРОВАННАЯ КОМПЬЮТЕРНАЯ АРХИТЕКТУРА С СОГЛАСОВАННЫМИ ОБЪЕКТАМИ
Область техники
Настоящее изобретение относится к компьютерной технике, а, более конкретно, к модифицированной машинной архитектуре, обеспечивающей выполнение программы приложения одновременно на нескольких компьютерах, соединенных друг с другом сетью связи.
Уровень техники
Первоначально, с момента появления компьютеров и вычислительной техники, программное обеспечение для компьютеров предназначалось для работы на одиночной машине. На фиг.1 показана такая известная из уровня техники одиночная машина 1, которая содержит центральный процессор 2 (ЦП), подсоединенный к запоминающему устройству 3 через шину 4. Также к шине 4 подсоединены различные функциональные блоки этой одиночной машины 1, такие как монитор 5, клавиатура 6 и мышь 7.
Производительность машины 1 значительно ограничена тем обстоятельством, что данные должны быть обработаны в ЦП 2, а результаты этих операций должны быть переданы по шине 4. Шина 4 испытывает целый ряд проблем, включая т.н. "очереди" на шине (создаваемые узлами, которые стремятся получить доступ к шине), проблемы конфликтов и т.п. Эти проблемы, до определенной степени, могут быть решены с помощью различных обходных путей, включающих использование кэш-памяти, однако все эти пути неизменно увеличивают для машины 1 затраты на управление.
Естественно, в течение всех лет компьютерной эры предпринимались различные попытки увеличить производительность машин. Один из таких подходов состоит в использовании множества симметричных процессоров. Этот подход на существующем уровне техники используется в т.н. суперкомпьютерах и схематически проиллюстрирован на фиг.2. Здесь множество процессоров 12 подсоединено к глобальной памяти 13. Однако, в каналах связи между процессорами 12 и памятью 13 опять возникают "узкие места". Этот процесс получил название "единый образ системы". Существует только одно приложение и одна полная копия памяти для этого приложения, которая распределена в глобальной памяти. Это одиночное приложение
WO 2005/103926
PCT/AU2005/000580
может считывать информацию и записывать ее (т.е. совместно использовать) в любой ячейке памяти совершенно прозрачным образом.
При наличии нескольких таких машин, взаимодействующих через сеть, указанный подход обеспечивается путем использования единственного приложения, написанного для одиночной машины, и разделения требуемых ресурсов памяти на части. Эти части далее распределяются между множеством компьютеров для создания глобальной памяти 13, доступной всем ЦП 12. Такая процедура основывается на маскировании (или сокрытии) разбиения памяти от единственной работающей прикладной программы. Производительность падает, когда один ЦП на одной машине вынужден обращаться (через сеть) по адресу памяти, физически находящемуся на другой машине.
Хотя суперкомпьютеры оказались технически успешными с точки зрения высокой скорости вычислений, они не имеют коммерческого успеха по причине присущей им сложности, которая делает необычайно дорогим не только их производство, но и управление ими. В частности, концепция единого образа системы так и не смогла выйти на рынок "товарных" (или массово используемых) компьютеров и сетей. В частности, концепция единого образа системы нашла практическое применение только в сверхбыстрых (а, следовательно, сверхдорогих) компьютерах, объединенных в сверхбыстрые (и такие же дорогие) сети.
Другая известная из уровня техники возможность увеличения мощности компьютеров путем использования нескольких машин обусловлена концепцией распределенных вычислений, схематически проиллюстрированной на фиг.З. Эта известная система предполагает, что одно приложение (Ар) разделено автором (или другим программистом, который ознакомился с приложением) на несколько отдельных задач, для выполнения, скажем, на трех машинах; в этом случае "п" на фиг.З - это целое число 3. Намерение здесь таково, что на каждой из машин Ml... МЗ выполняется соответствующая треть всего приложения и что нагрузка на разные машины примерно одинакова. Машины взаимодействуют через сеть 14, которая может быть представлена различными формами, например, канал связи, Интернет, Интранет, локальная сеть и т.д. Обычно скорость выполнения операций в таких сетях 14 на порядок меньше скорости выполнения операций шины 4 на каждой из отдельных машин Ml, М2 и т.д.
Распределенные вычисления имеют целый ряд недостатков. Во-первых, разделить приложение трудно и делать это нужно вручную. Во-вторых, передача по
WO 2005/103926
PCT/AU2005/000580
сети 14 данных, промежуточных результатов, результатов и т.п. обуславливает административные расходы. В-третьих, факт разделения чрезвычайно затрудняет расширение системы на большее число машин, поскольку приложение, разделенное, например, на три части, плохо выполняется на четырех машинах. В-четвертых, если одна из машин выходит из строя, то общая производительность всей системы значительно падает.
Следующая известная из уровня техники система основана на сетевых "кластерных" вычислениях. Она схематически проиллюстрирована на фиг.4. Согласно данному подходу приложение целиком загружают на каждую из машин Ml, М2 .... Мп. Каждая машина взаимодействует с общей базой данных, однако не взаимодействует напрямую с другими машинами. Хотя на каждой машине запущено одно и то же приложение, каждая из машин выполняет свое "задание" и использует только свою собственную память. Это немного похоже на ряд кассовых окошек, в каждом из которых продаются железнодорожные билеты пассажирам. Этот подход действительно работает и является расширяемым. Но он имеет недостаток, заключающийся в сложности администрирования такой сети.
В таких компьютерных языках, как JAVA и MICROSOFT.NET, программисты имеют дело с двумя основными типами конструкций. В языке JAVA эти конструкции известны как объекты и классы. Каждый раз при создании объекта запускается подпрограмма инициализации, известная как " ". Аналогично, каждый раз при загрузке класса запускается подпрограмма инициализации, известная как " ". В других языках используют иные термины, однако принцип остается тем же.
Однако нет эквивалентной подпрограммы "очистки" или удаления объекта или класса, когда они больше не нужны. Вместо этого "очистка" выполняется незаметно в фоновом режиме.
Кроме того, в любой вычислительной среде необходимо получать и снимать блокировку для разрешения использования конфигураций, ресурсов или структур, чтобы предотвратить ситуации, когда различные части приложения пытаются использовать одни и те же ресурсы одновременно. В среде JAVA это известно под названием "синхронизация". Она достигается в JAVA с помощью команд или
WO 2005/103926
PCT/AU2005/000580
подпрограмм "monitor enter" и "monitor exit". В других языках используют иные термины, однако принцип остается тем же.
В настоящем изобретении представлена компьютерная среда, в которой приложение работает одновременно на множестве компьютеров. В подобной среде необходимо обеспечить, чтобы вышеупомянутые процедуры инициализации, очистки и синхронизации выполнялись согласованно и скоординированно на всех машинах. Именно эта задача координации является целью настоящего изобретения.
В соответствии с первым аспектом настоящего изобретения, предложена многокомпьютерная система, имеющая по меньшей мере одно приложение, запущенное одновременно на множестве объединенных сетью связи компьютеров, в которой создано однородное множество идентичных по существу объектов, каждый из которых создается на соответствующем компьютере и имеет идентичное по существу имя, причем начальное содержание каждого из указанных идентично названных объектов по существу одинаково, при этом все указанные идентичные объекты одновременно удаляются, если каждый из указанного множества компьютеров более не нуждается в обращении к своим соответствующим объектам; также данная система содержит средство блокировки, применимое ко всем указанным компьютерам, при этом любой компьютер, намеревающийся использовать некий поименованный объект на нем, получает авторизационный блокиратор из указанного средства блокировки, который разрешает ему это использование и который предотвращает использование всеми другими компьютерами их соответствующих поименованных объектов до тех пор, пока указанный блокиратор не будет снят.
В соответствии со вторым аспектом настоящего изобретения предложен способ выполнения по меньшей мере одного приложения одновременно на множестве компьютеров, которые соединены друг с другом сетью связи, содержащий следующие шаги:
(i) создание однородного множества идентичных по существу объектов, каждый на соответствующем компьютере и каждый с идентичным по существу именем, (И) создание идентичного по существу начального содержания каждого из указанных идентично поименованных объектов,
WO 2005/103926
PCT/AU2005/000580
(iii) одновременное удаление всех указанных идентичных объектов, если все из указанного множества компьютеров более не нуждаются в обращении к своим соответствующим объектам,
(iv) предписание каждому из указанных компьютеров, намеревающемуся использовать некий поименованный на нем объект, получать авторизационный блокиратор, который разрешает ему это использование и который предотвращает использование всеми другими компьютерами их соответствующих поименованных объектов до тех пор, пока указанный блокиратор не будет снят.
В соответствии с третьим аспектом настоящего изобретения, предложен компьютерный программный продукт, содержащий набор команд. Этот продукт находится на носителе информации и может быть запущен на выполнение для реализации на множестве компьютеров вышеуказанного способа.
Краткое описание рисунков
Далее со ссылкой на приложенные рисунки описаны варианты выполнения данного изобретения, при этом:
Фиг.1 схематически изображает внутреннюю архитектуру обычного компьютера,
Фиг.2 схематически изображает внутреннюю архитектуру известной симметричной многопроцессорной системы,
Фиг.З схематически иллюстрирует известный из уровня техники способ распределенных вычислений,
Фиг.4 схематически иллюстрирует известный из уровня техники способ сетевых кластерных вычислений,
Фиг. 5 схематически изображает структурную схему множества машин, на которых запущено одно и то же приложение, в соответствии с первым вариантом настоящего изобретения,
Фиг.6 схематически изображает известный из уровня техники компьютер, выполненный с возможностью работы с JAVA-кодом и, таким образом, представляющий собой виртуальную JAVA-машину.
Фиг.7 - иллюстрация, сходная с фиг.6, но показывающая начальную загрузку кода в соответствии с предпочтительным вариантом изобретения,
WO 2005/103926
PCT/AU2005/000580
Фиг.8 - иллюстрация, сходная с фиг.5, но показывающая соединение друг с другом множества компьютеров, каждый из которых работает с JAVA-кодом таким же образом, как показано на фиг. 7,
Фиг. 9 изображает блок-схему процедуры, согласно которой одно и то же приложение загружается на каждую машину в сети,
Фиг. 10 изображает блок-схему, показывающую измененную процедуру, схожую с той, что показана на фиг.9,
Фиг. 11 схематически иллюстрирует многопоточную обработку, выполняемую показанными на фиг.8 машинами с использованием первого варианта обновления памяти,
Фиг. 12 - схематическое представление, сходное с фиг. 11, однако иллюстрирующее альтернативный вариант,
Фиг. 13 представляет многопоточное обновление памяти компьютеров, показанных на фиг.8,
Фиг. 14 схематически изображает известный из уровня техники компьютер, предназначенный для работы с JAVA-кодом и, таким образом, представляющий собой виртуальную JAVA-машину.
Фиг. 15 схематически изображает "п" машин, на которых запущено приложение и которые обслуживаются дополнительной серверной машиной X,
Фиг. 16 изображает блок-схему модифицированных подпрограмм инициализации,
Фиг. 17 изображает блок-схему, иллюстрирующую продолжение или прекращение работы подпрограмм инициализации,
Фиг. 18 изображает блок-схему, иллюстрирующую запрос, отсылаемый на серверную машину X,
Фиг. 19 изображает блок-схему ответа серверной машины X на запрос, показанный на фиг. 18,
Фиг.20 изображает блок-схему модифицированной подпрограммы инициализации для команды ,
Фиг.21 изображает блок-схему модифицированной подпрограммы инициализации для команды ,
Фиг.22 изображает блок-схему модифицированных подпрограмм "clean up" или финализации,
WO 2005/103926
PCT/AU2005/000580
Фиг.23 изображает блок-схему, иллюстрирующую продолжение или прекращение подпрограмм финализации,
Фиг.24 изображает блок-схему, иллюстрирующую запрос, отсылаемый на серверную машину X,
Фиг.25 изображает блок-схему ответа серверной машины X на запрос, показанный на фиг.24,
Фиг.26 изображает блок-схему модифицированных подпрограмм "monitor enter" и "exit",
Фиг.27 изображает блок-схему процесса, в соответствии с которым машина запрашивает получение блокиратора,
Фиг.28 изображает блок-схему, иллюстрирующую запрос на снятие блокиратора,
Фиг.29 изображает блок-схему ответа серверной машины X на запрос, показанный на фиг.27,
Фиг.30 изображает блок-схему, иллюстрирующую ответ серверной машины X на запрос, показанный на фиг.28,
Фиг.З 1 схематически изображает два портативных компьютера, соединенные для одновременного запуска группы приложений, причем оба приложения запущены на одном компьютере,
Фиг.32 - изображение, сходное с фиг.З 1, однако показывающее систему, представленную на фиг.З 1, в которой на каждом компьютере запущено по одному приложению,
и Фиг.ЗЗ - изображение, сходное с фиг.З 1 и 32, однако показывающее систему, представленную на фиг.З 1, в которой оба приложения одновременно запущены на обоих компьютерах.
Данное описание включает приложения А, В, С и D, в которых представлены фрагменты действительного программного кода, воплощающие различные аспекты описанных вариантов. Приложение А относится к полям, а приложение В относится к инициализации. Приложение С относится к финализации. Приложение D относится к синхронизации.
Подробное описание
Согласно фиг.5, иллюстрирующей предпочтительный вариант изобретения, одиночное приложение 50 может быть запущено одновременно на нескольких машинах
WO 2005/103926
PCT/AU2005/000580
Ml, M2 ... Mn, взаимодействующих по сети 53. Как станет ясно из нижеследующего, на каждой из машин Ml, М2...Мп запущено одно и то же приложение 50, и, таким образом, все машины Ml, М2.. .Мп имеют программный код и данные одного и того же приложения 50 Аналогично каждая из машин Ml, М2...Мп работает с одним и тем же (или по существу одним и тем же) модификатором 51, установленным на каждой из машин Ml, М2...Мп. То есть, все машины Ml, М2...Мп имеют один и тот же (или по существу один и тот же) модификатор 51, причем модификатор машины М2 обозначен как 51/2. Кроме того, во время загрузки (или до выполнения) приложения 50 на каждой из машин Ml, М2...Мп, каждое приложение 50 модифицируется соответствующим модификатором 51 по одним и тем же правилам (или по существу по одним и тем же правилам, поскольку допустимы незначительные оптимизационные изменения в каждом из модификаторов 51/1 ... 51/п).
Из вышеописанного следует, что если каждая из машин Ml, М2... Мп имеет ресурсы совместно используемой памяти, допустим 10 Мб, то объем общей совместно используемой памяти, доступной каждому из приложений 50, не 10п Мб, как можно было бы ожидать, а лишь 10 Мб. Однако далее поясняется, как это сказывается на улучшении работы. Естественно, каждая машина Ml, М2...Мп имеет ресурс нераспределенной памяти. Ресурсы нераспределенной памяти машин Ml, М2...Мп, как правило, приблизительно одинаковые, но это не является обязательным условием.
Из уровня техники известно управление машиной (произведенной каким-либо производителем и имеющей операционную систему, написанную на каком-либо языке) посредством какого-либо языка приложения с помощью создания виртуальной машины, как схематически показано на фиг.6. Известная из уровня техники система, показанная на фиг.6, имеет форму приложения 50, написанного на языке Java и исполняемого в рамках виртуальной Java-машины 61. Таким образом, если предполагаемый язык приложения - JAVA, то создается виртуальная JAVA-машина, которая способна работать с JAVA-кодом вне зависимости от производителя машины и ее внутренних особенностей. Более подробно об этом можно узнать в работе "The JAVA Virtual Machine Specification", 2-е издание, Lindholm & F. Yellin of Sun Microsystems Inc. США.
Согласно предпочтительному варианту данного изобретения, в эту хорошо известную показанную на фиг.6 систему внесены изменения, более конкретно - введено дополнительное средство, получившее название "распределенное исполнение
WO 2005/103926
PCT/AU2005/000580
программы" 71 или DRT ("distributed run time"), как показано на фиг.7. Согласно фиг.7 приложение 50 загружается на виртуальную JAVA-машину 72 через средство 71 распределенного исполнения программы в ходе процедуре загрузки, показанной стрелкой 75. Средство распределенного исполнения программы можно получить в Фонде Открытого Программного Обеспечения (Open Software Foundation) под названием Среда Распределенных Вычислений (Distributed Computing Environment, DCE). В частности, средство 71 распределенного исполнения программы приводится в действие во время процедуры загрузки JAVA-приложения 50, обозначенной стрелкой 75, чтобы первоначально создать виртуальную JAVA-машину 72. Последовательность операций, происходящих при загрузке, описана далее со ссылкой фиг.9.
На фиг.8 показана в модифицированной форме система с фиг.5, использующая виртуальные JAVA-машины, показанные на фиг.7. Ясно, что на каждую из машин Ml, М2...Мп загружается опять одно и то же приложение 50. Хотя взаимодействие между машинами Ml, М2...Мп, показанное стрелками 83, физически маршрутизируется аппаратными средствами машины, управление этим взаимодействием осуществляют индивидуальные средства DRT 71 /1...71 /п в каждой машине. Таким образом, на практике это можно концептуально выразить так: по сети 73 взаимодействуют скорее средства DRT 71/1...71/п, нежели сами машины Ml, М2...Мп.
Обратимся теперь к фиг.7 и 9. Во время процедуры 75 загрузки происходит модификация программы 50, загружаемой для создания виртуальной JAVA-машины 72. Эта модификация начинается на шаге 90 (фиг.9) и включает в себя начальный шаг 91 определения всех адресов памяти (называемых "полями" в JAVA, однако в других языках употребляются эквивалентные термины) в загружаемом приложении 50. Такие адреса памяти необходимо идентифицировать для последующей обработки на шагах 92 и 93. Средство DRT 71 во время процедуры 75 загрузки создает список всех идентифицированных таким образом адресов памяти, поля JAVA включены в список как объект и класс. В список включены как подвижные, так и синхронные поля.
На следующей фазе процедуры модификации (92 на фиг.9) происходит поиск в коде исполняемого приложения для обнаружения любого вычислительного процесса, который регулирует или изменяет значения полей из созданного на шаге 91 списка и, таким образом, осуществляет запись в поля, так что значение по соответствующему адресу памяти изменяется. Когда подобная операция (обычно на языке JAVA это
WO 2005/103926
PCT/AU2005/000580
"putstatic" или "putfield"), изменяющая значение поля, обнаружена, то в данном месте программы происходит вставка на шаге 93 "подпрограммы распространения обновлений", чтобы тем самым известить все другие машины об изменении значения данного поля. Далее, процедура загрузки продолжается в нормальном режиме, что показано шагом 94 на фиг.9.
Альтернативная форма начальной модификации во время загрузки изображена на фиг. 10. Здесь шаги "запуск" 90 и "создание списка" 91, а также шаг 92 поиска идентичны аналогичным шагам на фиг.9. Однако вместо вставки "подпрограммы распространения обновлений", как на шаге 93, в которой вычислительный поток производит обновление, происходит вставка "подпрограммы предупреждения" на шаге 103. "Подпрограмма предупреждения" дает команду потоку или потокам, не занятым в вычислениях и назначенным для DRT, выполнить необходимое распространение. Данный шаг 103 - более быстрая альтернативная процедура, снижающая временные издержки.
После того, как во время процедуры загрузки состоялась данная начальная модификация, осуществляется любая из многопоточных операций обработки, показанных на фиг. 11 и 12. На фиг. 11 показано, как происходит многопоточная обработка ПО на машинах, состоящая из потоков 111/1....111/4, причем обработка второго потока (в данном случае 111/2) заканчивается тем, что поток 111/2 на шаге 113 получает данные об изменении значения поля. На данном этапе нормальная обработка этого потока 111/2 останавливается на шаге 114, и тот же самый поток 111/2 передает по сети 53 всем другим машинам М2...Мп идентификатор измененного поля и измененное значение, изменение которого произошло на шаге 113. В конце этой процедуры взаимодействия поток 111/2 возобновляет обработку на шаге 115 до следующего экземпляра класса, где имеет место изменение значения поля.
Согласно альтернативной схеме, показанной на фиг. 12, как только поток 121/2 получает данные об изменении значения поля на шаге 113, он извещает DRT-обработку 120 (как показано на шаге 125 стрелкой 127) о том, что еще по меньшей мере один поток 121/1, назначенный для DRT-обработки 120, должен распространить, в соответствии с шагом 128, по сети 53 на все другие машины М2...Мп идентификатор измененного поля и измененное значение, обнаруженное на шаге 113. Данная операция может быть проведена быстро и, таким образом, обработка начального потока 111/2
WO 2005/103926
PCT/AU2005/000580
прерывается лишь на мгновение, как показано на шаге 125, перед тем, как поток 111/2 возобновляет обработку на шаге 115. Другой поток 121/1, который был извещен об изменении (как показано стрелкой 127), далее пересылает данные об этом изменении, как показано на шаге 128, через сеть 53 на каждую из других машин М2.. .Мп.
Эта вторая схема на фиг. 12 повышает эффективность использования вычислительных мощностей различных потоков 111/1...111/3 и 121/1 (которые, в общем случае, обслуживают неравные запросы) и дает улучшенную масштабируемость с увеличением числа "п" (здесь п - целое число, равное или большее 2, представляющее общее число машин, которые объединены сетью 53 и на которых одновременно запущено приложение 50). Вне зависимости от того, какая схема используется, измененное поле и идентификаторы, а также значения, обнаруженные на шаге ИЗ, распространяются на все другие машины М2...Мп в сети.
Это показано на фиг. 13, где средство DRT 71/1 и его поток 121/1 на фиг. 12 (представлен шагом 128 на фиг. 13) передает по сети 53 идентификатор и измененное значение адреса памяти из списка, возникшие на шаге 113 (фиг. 12) при обработке на машине Ml, на каждую из других машин М2...Мп.
Каждая из других машин М2...Мп выполняет действие, обозначенное шагами 135 и 136 на фиг. 13 для машины Мп, путем получения пары "идентификатор -значение" по сети 53 и записи нового значения по соответствующему локальному адресу памяти.
Согласно схеме, известной из уровня техники, в которой используется распределенное программное обеспечение (фиг.З), обращения программного обеспечения одной машины к памяти, физически расположенной на другой машине, разрешается сетью, связывающей эти машины. Однако такие обращения к памяти могут иметь своим следствием задержки вычислений порядка 106 - 107 циклов ЦП данной машины. Это обстоятельство в большой степени ответственно за снижение производительности в сети, объединяющей множество машин.
Однако понятно, что согласно настоящей схеме, описанной выше со ссылкой на фиг.8, все процессы чтения данных производятся локально, т.к. текущее значение всех полей сохранено на машине, выполняющей обработку, которая создает запрос на считывание памяти. Такая локальная обработка может быть выполнена в течение 102
WO 2005/103926
PCT/AU2005/000580
10 циклов ЦП. Таким образом, на практике по существу отсутствует задержки при обращениях к памяти, которые требуют процессов считывания.
Однако, как правило, прикладные программы считывают из памяти часто, а записывают в нее относительно редко. Как следствие, интенсивность, с которой в памяти записываются и перезаписываются данные, относительно невелика по сравнению со интенсивностью, с которой данные из памяти считываются. Таким образом, по причине небольшого числа запросов на запись и перезапись памяти, поля могут постоянно обновляться с относительно невысокой скоростью через недорогую обычную сеть 53, поскольку этой невысокой скорости достаточно для удовлетворения запросов прикладных программ на запись в память. В результате производительность схемы на фиг.8 намного превышает производительность схемы на фиг.З.
Согласно дополнительной модификации изобретения идентификаторы и значения измененных полей могут быть объединены в пакеты, чтобы еще более снизить требования к скорости взаимодействия в сети 53, соединяющей различные машины.
Специалистам данной области техники понятно, что в таблице, созданной каждым средством DRT 71 во время первоначальной записи полей, для каждого поля существует имя или идентификатор, являющийся общим для всей сети и опознаваемый всей сетью. Однако в каждой отдельной машине адрес памяти, соответствующий определенному поименованному полю, будет изменяться с течением времени, т.к. каждая машина будет последовательно сохранять измененные значения полей по различным адресам в соответствии со своими внутренними процессами. Таким образом, таблица в каждом средстве DRT будет иметь различающиеся адреса памяти, однако каждое глобальное "имя поля" будет иметь одно и то же "значение поля", записанное по различным адресам памяти.
Специалистам данной области техники также понятно, что вышеупомянутая модификация приложения во время загрузки может быть достигнута пятью способами, а именно:
(i) рекомпиляция во время загрузки,
(ii) процедура прекомпиляции перед загрузкой, (ш) компиляция перед загрузкой,
WO 2005/103926
PCT/AU2005/000580
(iv) динамическая компиляция,
(v) рекомпиляция после загрузки (или, например, до выполнения релевантного или соответствующего программного кода приложения в распределенной среде).
Традиционно термин "компиляция" обозначает изменение в коде или языке, например, изменение от источника к объектному коду, или от одного языка к другому. Однако следует понимать, что в данной заявке термин "компиляция" (и его грамматические эквиваленты) не является ограниченным, и может также включать в себя или охватывать модификации в пределах одного и того же кода или языка.
Согласно первому варианту изобретения отдельная машина, скажем, машина М2, загружает в себя код приложения, модифицирует его и затем загружает модифицированный код на каждую из машин Ml, МЗ ... Мп (последовательно или одновременно). Согласно данной схеме, которую можно назвать "ведущий/ведомый" ("master/slave"), каждая из машин Ml, МЗ, ... Мп загружает то, что ей выдает машина М2.
Согласно другому варианту изобретения каждая машина получает код приложения, но модифицирует его и загружает в себя модифицированный код. Это позволяет производить модификацию на каждой из машин немного иначе, оптимизируя ее на базе архитектуры и операционной системы данной машины, и все же эта модификация соответствует всем остальным подобным модификациям.
Согласно еще одной схеме, отдельная машина, скажем Ml, загружает немодифицированный код, а все остальные машины М2, МЗ ... Мп производят модификацию, чтобы удалить первоначальный код приложения и загрузить модифицированную версию.
В любом случае передача данных может быть или "ветвеобразной" (т.е. М2 передает данные на каждую из машин Ml, МЗ, М4 и т.д. напрямую) или "каскадной" или "последовательной" (т.е. М2 передает Ml, которая затем передает МЗ, которая затем передает М4, и т.д.).
Согласно еще одной схеме, машины Ml - Мп могут передавать все запросы на загрузку дополнительной машине (не показана), на которой не запущено данное
WO 2005/103926
PCT/AU2005/000580
приложение, которая выполняет модификацию посредством любого вышеизложенного метода и возвращает модифицированную подпрограмму на каждую из машин Ml - Мп, которые затем загружают модифицированную подпрограмму локально. По данной схеме машины Ml - Мп направляют все запросы на загрузку на данную дополнительную машину, которая возвращает модифицированную подпрограмму на каждую из этих машин. Объем правовой охраны данного изобретения распространяется на любые модификации, выполняемые этой дополнительной машиной.
Специалисты в области компьютерных технологий знают, что существуют по меньшей мере четыре технологии внесения модификаций в компьютерный код. Первая состоит в том, чтобы вносить модификации в исходный язык (язык-источник). Вторая заключается в том, чтобы конвертировать исходный код (скажем, JAVA) в промежуточное представление (или промежуточный язык). После проведения такой конвертации проводится указанная модификация, а потом - обратная конвертация. Желаемым результатом этого является модифицированный JAVA-код.
Третья возможность - конвертация в машинный код (напрямую или через упомянутый промежуточный язык). Далее машинный код модифицируется перед загрузкой и исполнением. Четвертая возможность заключается в конвертации исходного кода в промежуточное представление, которое затем модифицируется и далее конвертируется в машинный код.
Настоящее изобретение охватывает все четыре пути модификации, а также комбинацию двух, трех или даже всех четырех этих путей.
Далее обратимся к фиг. 14, на которой схематически представлен известный из уровня техники компьютер, работающий как виртуальная JAVA-машина. Здесь машина (произведенная каким-либо производителем и имеющая операционную систему, работающую на каком-либо языке) может выполнять приложение 50 на конкретном языке, в данном примере на языке JAVA. Таким образом, виртуальная JAVA-машина 72 способна работать с кодом 50 на языке JAVA и использовать JAVA-архитектуру вне зависимости от производителя машины и ее внутреннего устройства.
WO 2005/103926
PCT/AU2005/000580
На языке JAVA подпрограмма инициализации отрабатывает только один раз, когда загружается файл 50А данного класса. Однако подпрограмма инициализации работает часто, например, каждый раз, когда создается новый объект 50Х, 50Y и 50Z. К тому же классы загружаются ранее объектов, так что в приложении, показанном на фиг. 14 и имеющем только один класс 50А и три объекта 50X-50Z, первый класс 50А загружается в первую очередь, затем загружается первый объект 5 ОХ, затем второй объект 50Y и наконец загружается третий объект 50Z. Если, как на фиг. 14, имеется только одиночный компьютер или машина 72, то при выполнении подпрограмм инициализации, которые должны выполняться во время процедуры загрузки, не возникнет конфликтов или противоречий.
Однако на схеме, показанной на фиг.8 (а также на фиг.З 1-33), имеется
множество отдельных компьютеров или машин Ml, М2.....Мп, соединенных сетью 53
связи, для каждого из которых предусмотрен модификатор 51 и на каждый из которых загружено общее приложение 50. По существу, модификатор 51 должен воспроизвести идентичную структуру и содержание памяти на каждой из отдельных машин Ml, М2...Мп. Из этого следует, что в такой компьютерной среде необходимо удостовериться, что все отдельные машины инициализированы непротиворечивым образом. Модифицирующую функцию показанного на фиг. 5 модификатора 51 обеспечивает средство DRT 71, показанное на фиг.8.
Чтобы обеспечить согласованную инициализацию, приложение 50 подвергают тщательной проверке для выявления тех шагов программы, которые определяют подпрограмму инициализации. Данная поверка может иметь место или до загрузки, или во время процедуры 75 загрузки, или даже после процедуры 75 загрузки (однако до выполнения соответствующего релевантного кода приложения). Это можно сравнить с процедурой компиляции, понимая, что термин "компиляция" обычно подразумевает изменение кода или языка, например, из исходника в объектный код или из одного языка в другой. Однако в настоящем примере термин "компиляция" (и его грамматические эквиваленты) не является ограниченным и распространяется на модификации в рамках самого кода или языка.
Как следствие, при вышеупомянутой проверке первоначально ведется поиск подпрограмм , а когда они найдены, происходит вставка модифицирующего
WO 2005/103926
PCT/AU2005/000580
кода (обычно несколько команд) с созданием модифицированной подпрограммы . Эта модифицированная подпрограмма нужна для загрузки класса 50А на одну из машин, например, JVM#1, и для извещения всех других машин М2...Мп о том, что такой класс 50А существует, и о его нынешнем состоянии. Данная модификация и загрузка могут быть выполнены в нескольких различных режимах.
Так, в одном из режимов средство DRT 71, производящее загрузку машины, в данном случае JVM#1, запрашивает DRT 71/2...71/п всех других машин, инициализирован ли уже первый класс 50А. Если ответ на это вопрос "да", то нормальная процедура инициализации выключается или запрещается Если же ответ "нет", то проводится нормальная процедура инициализации и последующие изменения, проводимые во время этой процедуры, передаются всем остальным машинам, что обозначено стрелкой 83 на фиг.8.
Схожая процедура происходит каждый раз при загрузке объекта, скажем, 50Х, 50Y или 50Z. Если DRT 71/1 не определяет в результате опроса, загружен или нет конкретный объект, скажем объект 50Y, на другие машины М2...Мп, то DRT 71/1 запускает процедуру инициализации объекта и загружает на каждую из других машин М2...Мп эквивалентный объект (к которому удобно применить термин "равноправный объект") вместе с копией первоначальных значений. Однако, если DRT 71/1 определяет, что объект 50Y, о котором идет речь, уже существует на других машинах, то происходит запрет нормальной функции инициализации и создается локальная копия вместе с копией текущих значений. Желаемый результат опять же можно получить различными путями.
На фиг. 15 показана модификация общей схемы с фиг.8, при этом машины Ml, М2...Мп являются теми же, что и до этого, и на всех машинах Ml, М2...Мп одновременно запущено одно и то же приложение (или приложения) 50. Однако к предыдущей схеме добавлена серверная машина X, которая способна выполнять функцию обслуживания и, в частности, инициализацию, очистку и/или синхронизацию структур, конфигураций и ресурсов. В качестве такой серверной машины X можно использовать недорогой бытовой компьютер, например PC, поскольку вычислительная нагрузка на него является невысокой. Как обозначено пунктирными линиями на фиг. 15, можно использовать две серверные машины X и Х+1 с целью дублирования, чтобы повысить общую надежность системы. Если используются две такие серверные
WO 2005/103926
PCT/AU2005/000580
машины X и Х+1, то предпочтительно, чтобы они работали как сдвоенная машина в кластере. Дополнительная машина Х+1 является опциональной, что показано пунктирными линиями на фиг. 15.
Однако, серверную машину X можно и не добавлять, поскольку ее вычислительная нагрузка может быть распределена между машинами Ml, М2...Мп. Как альтернатива, для реализации функции обслуживания можно на одной из машин использовать базу данных (по схеме "ведущий/ведомый").
На фиг. 16 показана предпочтительная обобщенная процедура, которую необходимо выполнить для инициализации. После того, как будет начато выполнение шага загрузки 161, последовательно рассматриваются команды, которые необходимо выполнить, на предмет выявления всех подпрограмм инициализации, как показано на шаге 162. На языке JAVA это подпрограммы и (или "методы" по терминологии JAVA) В других языках используют иные термины.
Если на шаге 162 выявлена подпрограмма инициализации, то она модифицируется на шаге 163 обычно посредством вставки в подпрограмму дополнительных команд. Как альтернатива, модифицирующие команды могут быть вставлены до подпрограммы. После завершения шага модификации 163 процедура загрузки продолжается, как показано на шаге 164.
На фиг. 17 представлена конкретная форма модификации. После начала подпрограммы на шаге 171 структурам, конфигурациям или ресурсам (в терминологии JAVA - классы или объекты), которые необходимо инициализировать, присваивается на шаге 172 имя или тег, которые могут быть использованы глобально всеми машинами. Удобнее всего выполнять это с помощью таблицы, поддерживаемой серверной машиной X, показанной на фиг. 15. Данная таблица также содержит статус класса или объекта, подлежащих инициализации.
Как показано на фиг. 17, если на шагах 173 и 174 определено, что глобальное имя еще не инициализировано в другом месте (т.е. на машине, отличной от машины, которая выполняет загрузку), то это означает, что объект или класс могут быть инициализированы нормальным образом путем выполнения шага 176, поскольку это первый такой объект или класс, который необходимо создать.
WO 2005/103926
PCT/AU2005/000580
Однако, если на шагах 173 и 174 определено, что глобальное имя уже использовано где-либо, то это означает, что другая машина уже инициализировала данный класс или объект. Как следствие, обычная подпрограмма инициализации полностью прерывается выполнением шага 175.
На фиг. 18 проиллюстрирован запрос от машины, производящей загрузку (одна из машин Ml, М2...Мп), к показанной на фиг. 15 серверной машине X. Работа производящей загрузку машины временно прерывается, как показано на шаге 181, пока не будет получен ответ от машины X, как показано на шаге 182.
Фиг. 19 иллюстрирует процессы, выполняемые показанной на фиг. 15 машиной X в ответ на запрос, показанный на фиг. 18 шагом 181. Статус инициализации определяется на шагах 192 и 193, и, если инициализация уже выполнена, то ответ с этим содержанием посылается на запрашивающую машину выполнением шага 194. Аналогично, если статусом инициализации является "не инициализировано", то отсылается соответствующий ответ выполнением шагов 195 и 196. Ждущая запрашивающая машина, созданная на шаге 182, далее может ответить соответствующим образом.
В заявке делается ссылка на сопровождающие приложения, из которых: приложения А1-А10 показывают актуальный код в отношении полей, приложение В1 - это типичный фрагмент кода немодифицированной подпрограммы ,
приложение В2 - это эквивалент в отношении модифицированной подпрограммы ,
приложение ВЗ - это типичный фрагмент кода из немодифицированной подпрограммы ,
приложение В4 - это эквивалент в отношении модифицированной подпрограммы ,
Приложение В5 - это код, альтернативный коду приложения В2,
и приложение В6 - это код, альтернативный коду приложения В4.
Приложение В7 - это исходный код InitClient, который запрашивает "сервер
инициализации" о статусе инициализации соответствующего класса или объекта.
Приложение В8 - это исходный код InitServer, который получает запрос о статусе
инициализации от InitClient и в ответ сообщает соответствующий статус.
WO 2005/103926
PCT/AU2005/000580
Аналогично, приложение В9 - это исходный код примера приложения, которое используется в примерах до/после приложений В1-В6.
На фиг.20 показана процедура, которая должна быть выполнена для модификации подпрограммы в отношении классов так, чтобы произвести конвертацию фрагмента кода приложения В1 во фрагмент кода приложения В2. Первоначальная загрузка приложения 50 на виртуальную JAVA-машину 72 начинается на шаге 201, и каждая строка кода проверяется выполнением шага 202 для обнаружения тех команд, которые представляют подпрограмму . Как только такие команды обнаружены, подпрограмма модифицируется, как показано в приложении В2, выполнением шага 203. Как показано на шаге 204, после того, как модификация завершена, продолжается процедура загрузки.
Приложения В1 и В2 - это выборка до и после команды , соответственно. Модифицированный код, который добавлен в данный метод, выделен жирным шрифтом. В примере исходного кода приложения В1 метод создает новый собственный объект и записывает его по адресу памяти (поле) с именем "thisTest". Таким образом, в отсутствии управления загрузкой классов в распределенной среде каждая машина реинициализировала бы один и тот же общий адрес памяти (поле) с различными объектами. Естественно, это совсем не то, чего ожидает программист загружаемого приложения.
Тогда, используя преимущества DRT, код приложения модифицируется путем изменения метода во время загрузки в машину. Вносимые изменения (выделенные жирным шрифтом) - это первоначальные команды, которые выполняет метод . Эти добавленные команды проверяют, загружен ли уже этот класс, путем вызова метода isAlreadyLoaded(), который возвращает истинное или ложное значение в соответствии с состоянием загрузки данного класса.
Метод isAlreadyLoaded() средства DRT может опционально использовать для определения статуса загрузки данного класса аргумент, который представляет уникальный идентификатор для данного класса (см. приложения В5 и В6), например, имя класса, или объект класса, представляющий данный класс, или уникальный номер, представляющий данный класс на всех машинах. Таким образом, данное средство DRT
WO 2005/103926
PCT/AU2005/000580
может поддерживать одновременную загрузку множественных классов без ошибок относительно того, какой из множественных классов уже загружен, а какой - нет, используя уникальный идентификатор каждого класса для сверки с нужной записью в таблице isAlreadyLoaded.
Средство DRT может определить статус загрузки этого класса несколькими способами. Предпочтительно оно может опрашивать каждую машину по очереди, загружен ли данный класс, и, если какая-либо из машин отвечает "истинно", то возвращать значение "истинно", в противном случае - "ложно". Как альтернатива, средство DRT на локальной машине может обращаться к общей таблице записей (возможно, на отдельной машине (напр. на машине X), или к согласованной общей таблице записей на локальной машине, или к базе данных), чтобы определить, загружен уже данный класс или нет.
Если средство DRT возвращает значение "ложно", то это означает, что данный класс еще не был загружен ни на одну из машин в распределенной среде, и, следовательно, данное выполнение следует рассматривать как первое и исходное. Как следствие, средство DRT должно обновить запись "isAlreadyLoaded" для данного класса в общей таблице записей, придав ей значение "истинно", чтобы все последующие запросы isAlreadyLoaded на всех других машинах, включая данную машину, возвращали значение "истинно". Таким образом, если DRT.isAlreadyLoaded() возвращает значение "ложно", то модифицированный метод продолжает работать с исходным блоком кода, который теперь отслеживает три вставленные команды.
С другой стороны, если средство DRT возвращает значение "истинно", то это означает, что данный класс уже был загружен в распределенную среду, что записано в общей таблице записей загруженных классов. В этом случае исходный блок кода НЕ должен выполняться, поскольку он перезапишет уже инициализированные адреса памяти, и т.д. Таким образом, если DRT возвращает значение "истинно", то вставленные три команды предотвращают выполнение исходного кода и возвращают непосредственно в программу приложения.
WO 2005/103926
PCT/AU2005/000580
Эквивалентная процедура для подпрограмм в отношении объектов показана на фиг.21, где шаги 212 и 213 эквивалентны шагам 202 и 203 на фиг.20. В результате код приложения ВЗ конвертируется в код приложения В4.
Модификация, подобная используемой для , используется для . Блок программы приложения (или блоки, поскольку их может быть несколько в отличие от ) обнаруживается (или обнаруживаются), как показано на шаге 212, и модифицируется, как показано на шаге 213, для того, чтобы согласовано функционировать во всей распределенной среде.
В примере приложения ВЗ <1т1> -команды программы приложения инициализируют адрес памяти (поле) с меткой времени загрузки. Приложение могло бы использовать это, например, для записи времени создания данного объекта. Ясно, что в распределенной среде, где равноправные объекты могут быть загружены в разное время, необходима особая обработка для того, чтобы гарантировать, что метка времени первого загруженного равноправного объекта не будет перезаписана последующими равноправными объектами.
Последовательность деассемблированных команд после имевшей место модификации представлена в приложении В4, причем модифицированные/вставленные команды выделены жирным шрифтом. Для модификации , в отличие от модификации , часто необходимо размещать модифицирующие команды после команды "invokespecial", вместо размещения их в самом начале. Причины этого определяются свойствами виртуальной JAVA-машины. В других языках часто имеются похожие тонкие особенности построения.
Дана фундаментальная концепция тестирования для определения, прошла ли уже инициализация или она не выполняется, и если так, то не производить какую бы то ни было дальнейшую инициализацию; данная концепция может быть реализована несколькими различными вариантами.
В первом варианте отдельная машина, например машина М2, загружает класс или объект в себя, а затем загружает в каждую из других машин Ml, МЗ ... Мп (последовательно или одновременно). Согласно данной схеме, которую можно назвать
WO 2005/103926
PCT/AU2005/000580
"ведущий"/"ведомый" ("master/slave"), каждая из машин Ml, МЗ, ... Мп загружает то, что выдает ей машина М2.
В подварианте этой схемы "ведущий'У'ведомый", машина М2 загружает в себя подпрограмму в немодифицированной форме, а затем модифицирует данный класс путем полного удаления подпрограммы инициализации и загружает этот модифицированный класс в другие машины. Таким образом, в данном примере модификация - это не обход подпрограммы инициализации, а ее удаление на всех машинах, кроме одной.
В другом варианте каждая машина получает подпрограмму инициализации, но модифицирует ее и загружает модифицированную подпрограмму в себя. Это позволяет производить модификацию каждой машиной немного иначе, оптимизируя ее на основании архитектуры и операционной системы данной машины, и все же эта модификация соответствует всем остальным схожим модификациям.
Согласно еще одной схеме отдельная машина, скажем Ml, загружает этот класс, и все остальные машины М2, МЗ ... Мп производят модификацию, чтобы удалить подпрограмму инициализации и загрузить модифицированную версию.
Во всех примерах передача данных может быть или "ветвеобразной" (т.е. М2 передает данные каждой из машин Ml, МЗ, М4 и т.д. напрямую), или "каскадной" или "последовательной" (т.е. М2 передает Ml, которая затем передает МЗ, которая затем передает М4, и т.д.).
Согласно еще одной схеме первоначальная машина, например М2, может выполнить начальную загрузку, а затем создать таблицу, в которой перечислены все классы, загруженные машиной М2. Эту таблицу затем передают на все другие машины (путем ветвеобразной или каскадной передачи). Если затем какая-либо машина, отличная от М2, требует доступ к классу, включенному в эту таблицу, то она посылает на М2 запрос о предоставлении необходимой информации. Таким образом, информация, предоставленная машине Мп, в общем случае отличается от начального состояния, загруженного в машину М2.
WO 2005/103926
PCT/AU2005/000580
В вышеописанных условиях необходимо, чтобы каждая из записей этой таблицы сопровождалась счетчиком, увеличивающимся каждый раз при загрузке класса. Таким образом, когда получен запрос данных, в ответ на запрос поступает и содержимое класса, и отсчет соответствующего счетчика. Этот режим "по запросу" увеличивает непроизводительные расходы каждого компьютера, однако уменьшает объем передаваемых данных в сети связи, соединяющей эти компьютеры.
Согласно еще одной схеме машины Ml - Мп могут посылать все запросы на загрузку на дополнительную машину X (показана на фиг. 15), которая выполняет модификацию посредством любого из вышеописанных способов и возвращает модифицированный класс на каждую из машин Ml - Мп, которые затем загружают этот класс локально. В этой схеме машины Ml - Мп не поддерживают таблицу записей для любого класса, вместо этого они пересылают все запросы на загрузку машине X, которая поддерживает таблицу загруженных классов и возвращает модифицированный класс на каждую машину в зависимости от того, в первый раз данный класс загружается на машины М1...Мп или нет. Объем правовой охраны настоящего изобретения включает в себя любые модификации, выполняемые машиной X.
Обратимся опять к фиг. 14. На языке JAVA подпрограмма инициализации отрабатывает только один раз, когда происходит загрузка файла 50А данного класса. Однако подпрограмма инициализации отрабатывает часто, например, каждый раз, когда происходит создание нового объекта 50Х, 50Y или 50Z. К тому же загрузка классов происходит ранее загрузки объектов, так что в программе приложения, показанной на фиг. 14 и имеющей только один класс 50А и три объекта 50X-50Z, в первую очередь происходит загрузка первого класса 50А, затем загрузка первого объекта 50Х, затем второго объекта 50Y и, наконец, происходит загрузка третьего объекта 50Z. Если, как на фиг. 14, существует только одиночный компьютер или машина 72, то при запуске подпрограмм, которые должны быть выполнены во время процедуры загрузки, не возникает конфликтов или противоречий, поскольку эта показанная на фиг. 14 одиночная машина может легко отслеживать, необходимы ли конкретные объекты 50X-50Z в будущем для программы 50. Это достигается с помощью поддержки "подсчета идентификаторов" или аналогичной процедуры. Этот подсчет отслеживает число мест в исполняемом коде, в которых есть ссылка на какой-либо конкретный объект. Если подсчет идентификаторов для какого-либо конкретного
WO 2005/103926
PCT/AU2005/000580
объекта дает нулевое значение, то это значит, что нигде в исполняемом коде нет ссылок на этот объект. В этом случае такой объект называют "финализируемым" (finalizable).
Если достигнуто такое состояние, то этот объект может быть безопасно удален (или очищен, или финализирован), поскольку он больше не нужен. Та же процедура с соответствующими поправками применима к классам. В частности, программисту, который создает программу с использованием языка и архитектуры JAVA, не нужно писать какой-либо специфический код, чтобы обеспечить эту очистку, удаление или финализацию. Вместо этого отдельная виртуальная машина JAVA 72 может отслеживать подсчеты идентификаторов классов и объектов и выполнять очистку (или выполнять финализацию) при необходимости незаметным образом.
Однако на схеме, показанной на фиг.8 (а также на фиг.З 1-33), есть множество
отдельных компьютеров (или машин) Ml, М2 .....Мп, каждый из которых соединен
сетью 53 связи и каждый из которых снабжен модификатором 51 (как на фиг. 5, что реализовано средством DRT 71 на фиг.8), на которые загружена общая программа 50 приложения. По существу модификатор 51 или средство DRT 71 модифицирует код 50 приложения для выполнения подпрограмм очистки на всем множестве отдельных машин Ml, М2...Мп. Таким образом, отсюда следует, что в такой вычислительной среде необходимо удостовериться, что каждая из отдельных машин финализирована непротиворечивым образом (относительно других машин).
В частности, в то время как одна какая-то машина (например, МЗ) может более не иметь обращений к объекту или классу, другая машина (скажем, М5) может по прежнему иметь необходимость обратиться к этому объекту или классу в будущем. Таким образом, если этот объект или класс был бы удален с машины МЗ, то, если бы М5 должна была произвести запись в этот объект и изменить его значение, это изменение значения не могло бы быть распространено на все машины Ml, М2...Мп, поскольку машина МЗ не содержала бы соответствующий объект в своей локальной памяти. Более того, если бы машина МЗ выполнила подпрограмму очистки на данном объекте или классе, то эта подпрограмма очистки произвела бы очистку не только для данного объекта на этой машине, но также для всех равноправных объектов на всех других машинах. Таким образом, этот объект на машине М5 был бы объявлен недействительным. Таким образом, идентичного по существу содержимого памяти
WO 2005/103926
PCT/AU2005/000580
машин Ml, M2...Mn, необходимого для одновременной работы одной и той же программы приложения, достичь бы не удалось.
Чтобы обеспечить непротиворечивую финализацию или очистку, программу 50 приложения подвергают проверке для обнаружения программных шагов, которые определяют подпрограмму очистки. Данная проверка может иметь место или до загрузки, или во время процедуры загрузки, или даже после процедуры загрузки (однако до выполнения соответствующей релевантной части кода 50 приложения). Это можно сравнить с процедурой компиляции, понимая, что термин "компиляция" обычно подразумевает изменение кода или языка, например, из исходника в объектный код или из одного языка в другой. Однако в настоящем случае термин "компиляция" (и его грамматические эквиваленты) не ограничен и может содержать широчайшие модификации в рамках самого кода или языка.
Как следствие, при вышеупомянутой проверке первоначально идет поиск подпрограмм очистки, а когда они найдены, происходит вставка модифицирующего кода для создания модифицированной подпрограммы очистки. Эта модифицированная подпрограмма должна прервать подпрограмму очистки на любой конкретной машине, если класс или объект, который нужно удалить, не помечен для удаления всеми другими машинами. Данная модификация и загрузка могут быть выполнены в нескольких различных режимах. В связи с этим, сделана ссылка на приложение С, в котором приведены примеры различных режимов очистки или финализации.
Так, в одном режиме средство DRT 71/1 на машине, производящей загрузку, в данном случае JVM#1, опрашивает средства DRT 71/2...71/п всех других машин М2...Мп, использован ли (т.е. не помечен для удаления), например, первый объект 50Х любой другой машиной М2...Мп. Если ответ на этот вопрос "да", то далее обычная процедура очистки отключается или запрещается для первого объекта 5 0Х на машине JVM#1. Если ответ "нет" (т.е. первый объект 50Х помечен для удаления на всех других машинах), то происходит выполнение обычной процедуры очистки, а первый объект 50Х удаляется не только на машине JVM#1, но и на всех других машинах М2...Мп. Предпочтительно задача очистки располагается на последней машине Ml, маркирующей объект или класс на удаление.
На фиг.22 показана предпочтительная обобщенная процедура, которую необходимо выполнить для финализации. После того, как было начато выполнение
WO 2005/103926
PCT/AU2005/000580
загрузки 161 А, команды, которые необходимо выполнить, рассматриваются последовательно, а все подпрограммы очистки выявляются, как показано на шаге 162А. На языке JAVA это является подпрограммой "finalizeO" (или "методом", по терминологии JAVA). В других языках используют иные термины.
Если обнаружена подпрограмма очистки, то она модифицируется на шаге 163 А, обычно путем вставки в подпрограмму дополнительных команд. Как альтернатива, модифицирующие команды могут быть вставлены перед подпрограммой. После завершения модификации процедура загрузки продолжается, как показано на шаге 164А.
На фиг.23 изображена конкретная форма модификации. Во-первых, структурам, конфигурациям и ресурсам (на языке JAVA они называются классами или объектами) 50А, 50X...50Y, которые являются потенциальными кандидатами на очистку, уже присвоено имя или тег, которые могут быть использованы глобально всеми машинами Ml, М2...Мп, как показано на шаге 172А. Предпочтительно это происходит во время первоначальной инициализации этих классов или объектов. Лучше всего выполнять это с помощью таблицы, поддерживаемой серверной машиной X. Данная таблица также содержит "статус очистки" этого класса или объекта. В предпочтительном варианте эта таблица также содержит счетчик, который записывает число машин, пометивших данный ресурс для удаления. Тогда общее значение счетчика, меньшее чем (п-1), обозначает статус "не очищать" для этого ресурса как сетевого целого.
Как показано на фиг.23, если глобальное имя не помечено для удаления на всех других машинах (т.е. на всех, кроме машины, предлагающей выполнить подпрограмму очистки), то это означает, что предложенная подпрограмма очистки объекта или класса должна быть прервана, поскольку этот объект или класс еще необходим, как показано на шаге 175 А.
Однако если глобальное имя помечено для удаления на всех машинах, то это означает, что ни одна другая машина не нуждается в этом классе или объекте. Как следствие, обычная подпрограмма очистки, показанная на шаге 176А, может и должна быть выполнена.
На фиг.24 показан запрос серверной машине X, сделанный машиной, которая предлагает выполнение подпрограммы очистки (одна из машин Ml, М2...Мп). Работа
WO 2005/103926
PCT/AU2005/000580
этой предлагающей машины временно прерывается, как показано на шаге 181А и 182А, до тех пор, пока не будет получен ответ от машины X, что показано на шаге 182А.
На фиг.25 показаны процессы, выполняемые машиной X в ответ на такой запрос. Статус очистки определен, как видно на шаге 192А, и если ответ "нет", то названный ресурс не помечают для удаления на (п-1) машинах (т.е. он где-либо используется), ответ с этим содержанием отсылается на запрашивающую машину 194А, однако счетчик "помечен для удаления" увеличивается на единицу, как показано на шаге 197А. Аналогично, если ответ - "да", то отсылается соответствующий ответ, как показано на шаге 195А. Далее ожидающая запрашивающая машина 182А может ответить соответствующим образом. Как показано пунктирными линиями на фиг.25, предпочтительно, чтобы в дополнение к ответу "да" на шаге 195А была обновлена общая таблица так, чтобы статус глобально поименованного ресурса был изменен на "очищен", что показано на шаге 196А.
Обратимся опять к фиг. 14. Одиночная машина, показанная на фиг. 14, может легко выполнить синхронизацию конкретных объектов 50X-50Z, если так было определено программистом в использовании подпрограммы синхронизации. Поскольку каждый объект существует только локально, одиночная виртуальная JAVA-машина 72 может обеспечить правильную синхронизацию объекта, как было определено программистом, и, таким образом, обеспечить использование объекта только одной частью исполняемого кода в каждый отдельный момент времени. Если предполагается использовать тот же самый объект другой частью исполняемого кода, то возможная конкуренция устраняется виртуальной JAVA-машиной 72 таким образом, что другие исполняемые части программы приложения должны ждать, пока не завершится ее первая часть.
Та же процедура с соответствующими поправками применима к классам 50А. В частности, программисту, создающему программу с использованием языка и архитектуры JAVA, нужно просто использовать подпрограмму (подпрограммы) синхронизации, чтобы обеспечить это устранение конфликтной ситуации. Таким образом, одиночная виртуальная JAVA-машина может отслеживать использование классов и объектов и избегать при необходимости любых соответствующих проблем незаметным образом. Процесс, обеспечивающий эксклюзивное использование только одного объекта или класса, называется "синхронизацией". На языке JAVA команды
WO 2005/103926
PCT/AU2005/000580
"monitorenter" и "monitorexit" обозначают конец и начало подпрограммы синхронизации, которая имеет своим результатом, соответственно, получение и освобождение "блокиратора", предотвращающего конфликтную ситуацию в отношении какого-либо ресурса.
Однако на схеме, показанной на фиг.8 (а также на фиг.З 1 - 33), есть группа
соединенных сетью 53 связи отдельных компьютеров или машин Ml, М2 ..... Мп,
каждый из которых снабжен модификатором 51 (как на фиг.5, что реализовано показанным на фиг.8 средством DRT 71). На эти компьютеры загружена общая программа 50 приложения. По существу, модификатор 51 или средство DRT 71 обеспечивает следующее условие - если часть программы 50 приложения, запущенной на одной из машин, эксклюзивным образом использует (например, посредством синхронизации) какой-либо конкретный ресурс, например, объекты 50X-50Z или класс 50А, то ни одна другая машина М2...Мп не будет использовать соответствующий ресурс в своей локальной памяти.
В частности, тогда как одна машина (например МЗ) эксклюзивным образом использует какой-либо объект или класс, другая машина (например М5) может также получить команду от исполняемого ею кода эксклюзивным образом использовать тот же объект или класс в то же самое время. В результате, если бы этот объект или класс эксклюзивным образом использовался обеими машинами, то поведение объекта и приложения как целого стало бы неопределенным, т.е. из-за отсутствия правильного эксклюзивного использования объекта, явно заданного программистом, возможно возникновение постоянной несовместимости между машинами М5 и МЗ. Таким образом, идентичного по существу содержимого памяти машин Ml, М2...Мп, необходимого для одновременной работы одной и той же программы приложения, достичь бы не удалось.
Чтобы обеспечить согласованную синхронизацию, программа приложения подвергается анализу для выявления шагов, определяющих подпрограмму синхронизации. Данная проверка может иметь место или до загрузки, или во время процедуры загрузки, или даже после процедуры загрузки (однако до выполнения соответствующей релевантной части кода программы). Это можно сравнить с процедурой компиляции, понимая, что термин "компиляция" обычно подразумевает
WO 2005/103926
PCT/AU2005/000580
изменение кода или языка, например, из исходника в объектный код или из одного языка в другой. Однако в настоящем случае термин "компиляция" (и его грамматические эквиваленты) не ограничен и может содержать широчайшие модификации в рамках самого кода или языка.
Далее сделаны ссылки на приложение D, в котором: приложение D1 - это типичный фрагмент кода из немодифицированной подпрограммы синхронизации,
и приложение D2 - это эквивалент в отношении модифицированной подпрограммы синхронизации,
Приложения D1 и D2 - это выборка до и после подпрограммы синхронизации, соответственно. Модифицированный код, который вставлен в этот метод, выделен жирным шрифтом. В образце исходного кода приложения D1 код увеличивает общий адрес памяти (счетчик) в рамках оператора синхронизации. Цель этого оператора синхронизации - обеспечить безопасность потоков операции приращения в многопоточных приложениях. Так, без управления синхронизацией в распределенной среде каждая машина выполняла бы синхронизацию изолированно, при этом возможно увеличивая общий счетчик, что может привести к возникновению условия состязания сигналов и к несогласованности памяти. Естественно, это совсем не то, чего ожидает программист программы приложения.
Таким образом, используя преимущества DRT, код приложения модифицируется во время загрузки в машину путем изменения подпрограммы синхронизации. Вносимые изменения (выделенные жирным шрифтом) - это первоначальные команды и завершающие команды, которые выполняет подпрограмма синхронизации. Эти добавленные команды проводят дополнительную синхронизацию на всех других машинах в распределенной среде, способствуя, таким образом, сохранению синхронного поведения программы приложения на множестве машин.
Метод acquireLock() средства DRT получает аргумент, который представляет уникальный идентификатор этого объекта (см. приложение D2), например, имя объекта, ссылку на объект, о котором идет речь, или уникальный номер, представляющий этот объект на всех узлах, с целью использования его для получения
WO 2005/103926
PCT/AU2005/000580
глобального блокиратора для конкретного объекта. Таким образом, средство DRT может поддерживать одновременную синхронизацию множества объектов без конфликтов относительно того, какие из множества объектов уже находятся в процессе синхронизации, а какие - нет, используя уникальный идентификатор каждого объекта для сверки с нужной записью в общей таблице синхронизации.
Средство DRT может определить состояние синхронизации этого объекта несколькими способами. Предпочтительно оно может опросить каждую машину по очереди, идет ли в настоящее время на ней синхронизация локальной копии этого объекта, и, если какая-либо из машин возвращает ответ "истинно", то ожидать, когда этот объект станет несинхронизируемым, в противном случае синхронизировать этот объект локально. Как альтернатива, средство DRT на локальной машине может обратиться к общей таблице записей (возможно, на отдельной машине (напр. на машине X), или к согласованной общей таблице записей на локальной машине, или к базе данных) для того, чтобы определить, помечен ли уже этот объект, как синхронизируемый любой другой машиной, и если это так, то ожидать, пока статус объекта не изменится на "несинхронизируемый", а затем получить блокиратор путем пометки объекта как синхронизируемого, в противном случае получить блокиратор, пометив этот объект как синхронизируемый этой машиной.
Если средство DRT определяет, что ни одна другая машина не имеет в данный момент блокиратора для этого объекта (т.е. ни одна другая машина не синхронизирует этот объект), то оно получает блокиратор для этого объекта на всех других машинах, например, путем изменения соответствующей записи в общей таблице состояний синхронизации или, как альтернатива, последовательно получает блокиратор на всех других машинах в дополнение к текущей машине. Выполнение исходного синхронизированного блока кода может быть начато только если эта машина успешно подтвердит, что ни одна другая машина на данный момент не синхронизирует этот объект, и она уже провела локальную синхронизацию.
С другой стороны, если средство DRT определяет, что другая машина уже синхронизировала данный объект, тогда эта машина должна отложить выполнение исходного блока кода синхронизации до тех пор, пока средство DRT не сможет подтвердить, что никакая другая машина в настоящий момент не выполняет оператор синхронизации для данного объекта и что эта машина, соответственно, выполнила
WO 2005/103926
PCT/AU2005/000580
синхронизацию данного объекта локально. В этом случае НЕ допускается выполнять исходный блок кода, пока эта машина не сможет гарантировать, что никакая другая машина не выполняет оператор синхронизации для данного объекта, поскольку это может исказить данный объект на всех участвующих машинах из-за возникновения условия состязания сигналов, несогласованности памяти и т.д., как результат одновременного выполнения операторов синхронизации. Таким образом, когда средство DRT определяет, что этот объект в настоящее время "синхронизируется", средство DRT предотвращает исполнение исходного блока кода путем приостановки выполнения операции "acquireLock()" до тех пор, пока соответствующая операция "acquireLock()" не будет выполнена текущим владельцем блокиратора.
Таким образом, после выполнения операции "releaseLock()" машина, которая в настоящий момент "владеет" блокиратором (т.е. выполняет оператор синхронизации), обозначает завершение своего оператора синхронизации, например, путем пометки данного объекта как "несинхронизируемого" в общей таблице состояний синхронизации или, как альтернатива, последовательно снимая блокираторы, полученные на всех других машинах. На этом этапе любая другая машина, ожидающая начала выполнения соответствующего оператора синхронизации, может далее запросить владение блокиратором этого объекта путем возобновления выполнения своей отложенной (т.е. задержанной) операции "acquireLock()", например, помечая себя в общей таблице состояний синхронизации как выполняющую оператор синхронизации для этого объекта, или, как альтернатива, последовательно получая локальные блокираторы на каждой из других машин.
Таким образом, используя преимущества средства DRT, во время загрузки в эту машину код приложения модифицируют путем изменения подпрограммы синхронизации (состоящей из начальной "monitorenter" и завершающей "monitorexit" команды/команд). Вносимые изменения (выделенные жирным шрифтом) - это первоначальные команды, которые выполняет подпрограмма синхронизации. Эти добавленные команды проверяют, получен ли уже этот блокиратор другой машиной. Если этот блокиратор еще не получен другой машиной, то средство DRT данной машины извещает все другие машины, что эта машина получила блокиратор, и, таким образом, удерживает другие машины от выполнения подпрограмм синхронизации для этого блокиратора.
Средство DRT может записывать статус блокиратора этих машин разными альтернативными способами, например:
WO 2005/103926
PCT/AU2005/000580
1. В соответствии со входом в подпрограмму синхронизации, средство DRT запрашивает у каждой из машин по отдельности подтверждение, получен ли уже блокиратор. Если так, то средство DRT приостанавливает выполнение подпрограммы синхронизации до тех пор, пока все другие машины не перестанут "владеть" блокиратором для этого ресурса или объекта. В противном случае средство DRT выполняет эту подпрограмму синхронизации.
2. В соответствии со входом в подпрограмму синхронизации, средство DRT обращается к общей таблице записей (например, к общей базе данных или к копии общей таблицы на каждой из участвующих машин), которые определяют, "владеет" ли блокиратором какая-либо из машин в настоящий момент. Если это так, то средство DRT приостанавливает выполнение подпрограммы синхронизации на этой машине до тех пор, пока все другие машины не перестанут "владеть" блокиратором для этого объекта. В противном случае средство DRT записывает эту машину в общую таблицу (или в таблицы, если существует множество таблиц записей, например, на множестве машин) в качестве владельца этого блокиратора, а затем выполняет подпрограмму синхронизации.
Аналогично, когда блокиратор снят, т.е., когда выполнение подпрограммы синхронизации завершено, средство DRT может убрать запись о статусе блокиратора машин несколькими альтернативными способами, например:
1. В соответствии с выходом из подпрограммы синхронизации, средство DRT извещает каждую другую машину по отдельности, что она более не "владеет" блокиратором.
2. В соответствии с выходом из подпрограммы синхронизации, средство DRT обновляет запись для этого заблокированного ресурса или объекта в общей таблице (таблицах) записей так, что данная машина более не является указанной в качестве владельца блокиратора.
Более того, средство DRT может ставить в очередь машины, желающие получить заблокированный объект, множеством альтернативных способов, например: 1. В соответствии со входом в подпрограмму синхронизации, средство DRT извещает текущего владельца заблокированного объекта о том, что некоторая конкретная машина хотела бы получить данный блокиратор после его освобождения текущей машиной-владельцем. Далее эта конкретная машина, если нет других
WO 2005/103926
PCT/AU2005/000580
ожидающих машин, сохраняет запись об интересе данной конкретной машины в таблице, которая после завершения синхронизирующей подпрограммы заблокированного объекта далее извещает ждущую машину, что та может получить этот заблокированный объект и, таким образом, начать выполнение своей подпрограммы синхронизации.
2. В соответствии со входом в подпрограмму синхронизации, средство DRT извещает текущего владельца заблокированного объекта, что некоторая конкретная машина (например, машина Мб) хотела бы получить блокиратор после его освобождения этой машиной (например, машиной М4). Если эта машина М4 после просмотра своих записей ждущих машин для этого заблокированного объекта обнаруживает, что уже одна или более машин находятся в ожидании, то она или добавляет машину Мб в конец списка машин, ожидающих получения данного заблокированного объекта, или, как альтернатива, перенаправляет запрос от машины Мб первой ждущей машине, или любой другой ждущей машине, которая, в свою очередь, записывает машину Мб в свою таблицу записей.
3. В соответствии со входом в подпрограмму синхронизации, средство DRT записывает себя в общую таблицу (таблицы) записей (например, в таблицу, хранящуюся в общей базе данных, доступной всем машинам, или во множество отдельных таблиц, которые по существу подобны).
Кроме того,' средство DRT может известить другие машины, ожидающие очереди на получение этого блокиратора, в соответствии с выходом из подпрограммы синхронизации этой машины, следующими альтернативными способами, например:
1. В соответствии с выходом из подпрограммы синхронизации, средство DRT извещает одну из ждущих машин (например, эту первую машину в очереди ждущих машин) о том, что блокиратор освобожден.
2. В соответствии с выходом из подпрограммы синхронизации, средство DRT извещает одну из ждущих машин (например, первую машину в очереди ждущих машин) о том, что блокиратор освобожден, и дополнительно обеспечивает копию всей очереди машин (например, вторая и последующие машины, ждущие этого блокиратора). Таким образом, вторая машина наследует список ждущих машин от первой машины, обеспечивая посредством этого непрерывность очереди ждущих машин, поскольку каждая последующая машина в списке по очереди получает, а затем освобождает блокиратор.
WO 2005/103926
PCT/AU2005/000580
В течение вышеупомянутой проверки сначала производится поиск команд (или методов) "monitor enter" и "monitor exit", а когда они выявлены, происходит вставка модифицирующего кода с целью создания модифицированной подпрограммы синхронизации. Эта модифицированная подпрограмма получает и освобождает блокиратор. Данная модификация и загрузка могут быть выполнены в нескольких различных режимах. Более подробная информация приведена в приложении D.
На фиг. 2 6 показана предпочтительная общая процедура, которую необходимо выполнить в отношении синхронизации. После того, как было начато выполнение загрузки 161В, последовательно рассматриваются команды, которые необходимо выполнить, и выявляются все подпрограммы синхронизации, как показано на шаге 162В. На языке JAVA - это команды "monitor enter" и "monitor exit". В других языках используют иные термины.
Если выявлена подпрограмма синхронизации, то она обычно модифицируется путем вставки дополнительных команд в подпрограмму. Как альтернатива, модифицирующие команды могут быть вставлены до подпрограммы. Когда модификация завершена, продолжается процедура загрузки. Модификации предпочтительно принимают форму операции "установить блокиратор на всех других машинах" и форму модификации "снять блокиратор на всех других машинах", как показано на шаге 163В.
На фиг.27 изображена конкретная форма модификации. Во-первых, структурам, конфигурациям и ресурсам (в языке JAVA они называются классами или объектами, например 50А, 50X-50Y), которые необходимо синхронизировать, уже присвоено имя или тег, которые могут быть использованы глобально всеми машинами, как показано на шаге 172В. Предпочтительно это происходит во время первоначальной инициализации этих классов или объектов. Лучше всего выполнять это с помощью таблицы, поддерживаемой серверной машиной X. Данная таблица также содержит статус синхронизации этого класса или объекта. В предпочтительном случае эта таблица также содержит схему очереди, которая хранит идентификаторы машин, запросивших использование данного ресурса.
WO 2005/103926
PCT/AU2005/000580
Как показано на фиг.27 шагом 173В, далее на машину X посылают запрос "получить блокиратор", после чего машина, пославшая запрос, ждет подтверждения о получении блокиратора, как показано на шаге 174В. Таким образом, если глобальное имя уже заблокировано (т.е. соответствующий ресурс используется машиной, отличной от той, которая послала запрос на получение блокиратора), то это означает, что предложенная подпрограмма синхронизации этого объекта или класса должна быть приостановлена до тех пор, пока этот объект или класс не будет разблокирован текущим владельцем.
Как альтернатива, если глобальное имя не заблокировано, то это означает, что никакая другая машина не использует в данный момент этот класс или объект, и подтверждение о получении блокиратора приходит немедленно. После получения подтверждения о получении блокиратора подпрограмме синхронизации разрешено продолжить работу, как показано на шаге 175В.
На фиг.28 показана процедура, выполняемая запросившей снятия блокиратора машиной, на которой запущена программа приложения. Начальный этап показан на шаге 181В. Работа этой предлагающей машины временно прервана на шагах 183В, 184В до тех пор, пока не получен ответ от машины X, соответственно шагу 184В, и далее выполнение возобновляется, как показано на шаге 185В. Опционально, и как показано на шаге 182В, машина, запрашивающая снятие блокиратора, должна выполнить поиск "глобального имени" для этого блокиратора до отправки запроса на машину X. Таким образом, множество блокираторов на множестве машин может быть установлено и снято без взаимных помех.
На фиг.29 показаны процессы, выполняемые машиной X в ответ на запрос "получить блокиратор" (фиг.27). После получения запроса "получить блокиратор" на шаге 191В, статус блокиратора определяют на шагах 192В и 193В, и если "нет", то названный ресурс не свободен, идентификатор запрашивающей машины добавляется на шаге 194В к очереди (или формирует ее) ждущих запросов на получение. Как альтернатива, если ответ "да", то названный ресурс свободен и соответствующий ответ послан на шаге 197В. Ждущие запрашивающие машины далее могут соответственно выполнить подпрограмму синхронизации путем выполнения шага 175В на фиг.27. В дополнение к ответу "да", общая таблица обновляется на шаге 196В, так что статус глобально поименованного ресурса меняется на "заблокирован".
WO 2005/103926
PCT/AU2005/000580
На фиг.30 показаны процессы, выполняемые машиной X в ответ на запрос "снять блокиратор" на фиг.28. После получения запроса "снять блокиратор" на шаге 201 машина X опционально и предпочтительно, подтверждает, что машина, запросившая снятие (освобождение) блокиратора, на самом деле является текущим "владельцем блокиратора", как показано на шаге 202. Далее, на шаге 203 определяют статус очереди, и, если никто не ждет получения этого блокиратора, то машина X помечает этот блокиратор как "свободный" в общей таблице, как показано на шаге 207, и опционально посылает подтверждение об освобождении блокиратора запрашивающей машине, как показано на шаге 208. Это позволяет запрашивающей машине выполнить шаг 185В фиг.28.
Как альтернатива, если "да", т.е. если другие машины ждут получения этого блокиратора, то машина X помечает этот блокиратор как полученный в данный момент времени следующей машиной в очереди, как показано на шаге 204, и затем посылает подтверждение о получении блокиратора стоящей в очереди машине на шаге 205, а, следовательно, удаляет нового владельца блокиратора из очереди ждущих машин, как показано на шаге 206.
Обратимся теперь к фиг.З 1 - 33; здесь показаны два портативных компьютера 101 и 102. Эти компьютеры 101 и 102 необязательно являются идентичными - один из них может быть IBM-совместимым или IBM-клоном, а другой может быть компьютером APPLE. Эти компьютеры 101 и 102 имеют два экрана 105, 115, две клавиатуры 106, 116, но одну мышь 107. Эти две машины 101, 102 связаны одиночным коаксиальным кабелем или витой парой 314.
Две простые программы приложения загружены в каждую из машин 101, 102, причем эти программы модифицируются при загрузке вышеописанным способом. Согласно этому варианту первое приложение - это простая вычислительная программа, обеспечивающая вывод изображения калькулятора 108 на экран 105. Вторая программа - это графическая программа, которая выводит изображение четырех окрашенных блоков 109, которые имеют разные цвета и перемещаются случайным образом в прямоугольной рамке 310. Опять же, после загрузки рамка 310 выводится на экран 105. Каждое приложение работает независимо, поэтому блоки 109 находятся в случайном движении по экрану 105, в то время как цифры калькулятора 108 могут быть выбраны
WO 2005/103926
PCT/AU2005/000580
(с помощью мыши 107) вместе с математическим оператором (например, сложение или умножение), а калькулятор отображает результат.
Мышь 107 может быть использована для "захвата" рамки 310 и перемещения ее вправо через экран 105 на экран 115 до положения, изображенного на фиг.32. В этой схеме приложение-калькулятор выполняется на машине 101, в то время как графическое приложение, выводящее рамку 310 на экран, выполняется на машине 102.
Однако, как показано на фиг.ЗЗ, с помощью мыши можно перетащить вправо калькулятор 108, показанный на фиг.32, так чтобы по одной части калькулятора 108 было выведено на каждом из экранов 105, 115. Аналогично, рамку 310, показанную на фиг.32, можно перетащить с помощью мыши 107 влево, чтобы рамка 310 была частично отображена на каждом из экранов 105, 115, как показано на фиг.ЗЗ. В данной схеме часть процессов калькулятора выполняет машина 101, а часть - машина 102, в то время как часть графического приложения выполняет машина 101, а другую часть выполняет машина 102.
В данной заявке описаны лишь некоторые варианты изобретения. Однако следует понимать, что их модификации, очевидные специалистам данной области техники, также подпадают под объем правовой охраны настоящего изобретения. Например, указание на JAVA подразумевает как язык JAVA, так и платформу и архитектуру JAVA. •
Специалисты, работающие в области программирования, знают, что если дополнительный код или команды добавлены в существующий код или набор команд для их модификации, то существующий код или набор команд вполне может потребовать дополнительной модификации (например, путем перенумерации последовательных команд), так что необходимо учитывать соответствующие смещения, ветвления, атрибуты, маркировка и т.д.
Аналогично, в языке JAVA адреса памяти включают в себя, например, как поля, так и регулярные типы. Вышеприведенное описание рассматривает поля. Однако следует понимать, что изменения, требуемые для регулярных типов являются по существу теми же самыми с соответствующими поправками. Также настоящее изобретение в равной степени применимо к разным языкам программирования (включая процедурные, декларативные и объектно-ориентированные), аналогичным
WO 2005/103926
PCT/AU2005/000580
языку JAVA, включая платформу и архитектуру Micrsoft.NET (Visual Basic, Visual С/С", and С#), FORTRAN, С/С4*, COBOL, BASIC и т.д.
Вышеупомянутый вариант, в котором модифицируется код JAVA подпрограммы инициализации, основан на предположении, что или система исполнения (например, JAVA HOTSPOT VIRTUAL MACHINE, написанная на С или JAVA), или операционная система (LINUX, написанная на С и Ассемблер, например) каждой из машин М1...Мп будет вызывать подпрограмму инициализации JAVA. Можно не изменять подпрограмму инициализации JAVA, а вместо этого изменить подпрограмму LINUX или HOTSPOT, которая вызывает подпрограмму инициализации JAVA, так что если объект или класс уже загружен, то подпрограмма инициализации JAVA не вызывается. Для того, чтобы принять такую схему, термин "подпрограмма инициализации" должен пониматься как включающий в себя и подпрограмму инициализации JAVA, и "комбинацию" подпрограммы инициализации JAVA и фрагментов кода LINUX или HOTSPOT, которые вызывают или инициируют подпрограмму инициализации JAVA.
Вышеупомянутый вариант, в котором модифицируется код подпрограммы финализации или очистки JAVA, основан на предположении, что или система исполнения (например, JAVA HOTSPOT VIRTUAL MACHINE, написанная на С или JAVA), или операционная система (LINUX, написанная на С и Ассемблер, например) каждой из машин М1...Мп будет вызывать подпрограмму финализации JAVA. Можно не изменять подпрограмму финализации JAVA, а вместо этого изменить подпрограмму LINUX или HOTSPOT, которая вызывает подпрограмму финализации JAVA, так что если объект или класс не должны быть удалены, то подпрограмма финализации JAVA не вызывается. Для того, чтобы принять такую схему, термин "подпрограмма финализации" следует понимать как включающий в себя и подпрограмму финализации JAVA, и "комбинацию" подпрограммы финализации JAVA и фрагментов кода LINUX или HOTSPOT, которые вызывают или инициируют подпрограмму финализации JAVA.
Вышеупомянутый вариант, в котором модифицируется код подпрограммы синхронизации JAVA, основан на предположении, что или система исполнения (например, JAVA HOTSPOT VIRTUAL MACHINE, написанная на С или JAVA), или операционная система (LINUX, написанная на С и Ассемблер, например) каждой из машин М1...Мп будет нормальным образом получать блокиратор на локальной
WO 2005/103926
PCT/AU2005/000580
машине (скажем, М2), но не на любой другой машине (Ml, МЗ ...Мп). Можно не изменять подпрограмму синхронизации JAVA, а вместо этого изменить подпрограмму LINUX или HOTSPOT, которая получает блокиратор локально, так что, соответственно, она также получает блокиратор на всех других машинах. Для того, чтобы принять такую схему, термин "подпрограмма синхронизации" следует понимать как включающий в себя и подпрограмму синхронизации JAVA, и "комбинацию" подпрограммы синхронизации JAVA и фрагментов кода LINUX или HOTSPOT, которые выполняют получение и освобождение блокиратора.
Термины объект и класс, используемые в данной заявке, взяты из среды JAVA, и подразумевается, что они включают в себя схожие термины, взятые из других сред, например, динамически компонуемые библиотеки (dynamically linked libraries = DLL), или пакеты объектного кода, или функциональный узел, или адреса памяти.
Используемый в заявке термин "содержащий" (и его грамматические эквиваленты) должен пониматься в инклюзивном смысле "вхождения" или "включения", но не в эксклюзивном смысле как "состоящий только из".
Уведомление об авторских правах
Эта заявка содержит материалы, которые являются субъектом охраны авторских прав. Владелец авторских прав (являющийся заявителем) не имеет возражений против публикации данной заявки или связанных с ней материалов патентным ведомством с целью обзора или рассмотрения, однако во всем остальном сохраняет все авторские права за собой. В частности, разнообразные команды нельзя вводить в компьютер без специального письменного разрешения данного владельца авторских прав.
PCT/AU2005/000580
Приложение А
Ниже следуют листинги программы на языке JAVA:
А1. Эта первая выборка - часть модифицирующего кода. Он проводит поиск в массиве кода и, обнаружив команду putstatic (код операции 178), производит модификацию.
// START
byte[] code = Code_attribute.code; // Bytecode of a given method in a
// given classfile.
int code_length = Code_attribute.code_length;
int DRT = 99; // Location of the CONSTANT_Methodref_infо for the
// DRT.alert() method.
for (int i=0; i if ((codefi] 4 Oxff) == 179){ // Putstatic instruction.
System.arraycopy(code, i+3, code, i+6, code_length-(i+3));
code[i+3] = (byte) 184; // Invokestatic instruction for the
// DRT.alert!) method.
code[i+4] = (byte) ( (DRT "> 8) & Oxff);
code[i+5] = (byte) (DRT 4 Oxff);
// END
A2. Эта вторая выборка - часть метода DRT.alert(). Это тело метода DRT.alert() в момент его вызова.
// START
public static void alert О{ synchronized (ALERT_LOCK){
ALERT_LOCK.notify(); // Alerts a waiting DRT thread in the background.
// END
A3. Это третья выборка - часть процедуры DRT Sending. Данный фрагмент кода показывает, как DRT в отдельном потоке, после получения извещения, посылает это значение по сети.
// START
MulticastSocket ms = DRT.getMulticastSocket() ; // The multicast socket
// used by the DRT for // communication.
WO 2005/103926
PCT/AU2005/000580
byte nameTag =33; // This is the "name tag" on the network for this
// field.
Field field = modifiedClass.getDeclaredFieldC'myFieldl") ; // Stores
// the field
// from the
// modified
// class.
// In this example, the field is a byte field, while (DRT.isRunningO ) {
synchronized (ALERT_LOCK){
ALERT_LOCK.wait(); // The DRT thread is waiting for the alert
// method to be called.
byte[] b = new byte[]{nameTag, field.getByte(null)}; // Stores
// the
// nameTag
// and the
// value
// of the
// field from
// the modified
// class in a
// buffer.
DatagramPacket dp = new DatagramPacket(b, 0, b.length); ms.send(dp); // Send the buffer out across the network.
// END
A4 Четвертая выборка - это часть процедуры DRT receiving. Это фрагмент кода для получения отосланного DRT по сети уведомления.
// START
MulticastSocket ms = DRT.getMulticastSocket() ; // The multicast socket
// used by the DRT for
// communication.
DatagramPacket dp - new DatagramPacket(new byte[2], 0, 2);
byte nameTag = 33; // This is the "name tag" on the network for this
// 'field.
Field field = modifiedClass.getDeclaredField("myFieldl"); // Stores the
// field from // the modified // class.
// In this example, the field is a byte field, while (DRT.isRunning){
ms.receive(dp); // Receive the previously sent buffer from the network. byte[] b = dp.getData();
if (b[0] == nameTag){ // Check the nametags match.
field.setByte(null, b[l]); // Write the value from the network packet
// into the field location in memory.
WO 2005/103926
PCT/AU2005/000580
// END
A5 Пятая выборка - пример приложения до проведения модификации. Method void setValues(int, int)
0 iloadj
1 putstatic #3
4 aload_0
5 iload_2
6 putfield #2 9 return
A6. Шестая выборка - тот же пример приложения, что и в 5, после того, как была выполнена модификация. Модификации выделены жирным шрифтом. Method void setValues(int, int)
0 iloadj
1 putstatic #3 4 ldc #4
6 iconst_0
7 invokestatic #5
10aload_0 lliload_2
12 putfield #2
15 aload_0
16 iconst_l
17 invokestatic #5
20 return
A7. Седьмая выборка - это исходный код примера приложения, использованного в выборке 5 и 6.
import j ava.lang.*;
public class example!
/** Shared static field. */ public static int staticValue = 0;
/** Shared instance field. */ public int instanceValue = 0;
/** Example method that writes to memory (instance field). */ public void setValues(int a, int b){
staticValue " a;
instanceValue " b;
A8. Восьмая выбора ~ это исходный код FieldAlert, который извещает "распределенное выполнение" о необходимости распространить измененное значение.
WO 2005/103926
PCT/AU2005/000580
import java.lang.*; import java.util.*; import java.net.*; import java.io.*; public class FieldAlert{
/** Table of alerts. */
public final static Hashtable alerts = new HashtableO;
/** Object handle. */
public Object reference = null;
/** Table of field alerts for this object. */ public boolean[] fieldAlerts = null;
/** Constructor. */
public FieldAlert(Object o, int initialFieldCount){ reference = o;
fieldAlerts = new boolean[initialFieldCount];
/** Called when an application modifies a value. (Both objects and classes) */
public static void alert(Object o, int fieldID){
// Lock the alerts table, synchronized (alerts)(
FieldAlert alert = (FieldAlert) alerts.get(o);
if (alert == null)( // This object hasn't been alerted already,
// so add to alerts table, alert = new FieldAlert(o, fieldID + 1); alerts.put(o, alert);
if (fieldID > = alert.fieldAlerts.length){ // Ok, enlarge fieldAlerts array, boolean[] b = new boolean[fieldID+1]; System.arraycopy(alert.fieldAlerts, 0, b, 0,
alert.fieldAlerts.length); alert.fieldAlerts " b;
// Record the alert.
alert.fieldAlerts[fieldID] = true;
// Mark as pending.
FieldSend.pending = true; // Signal that there is one or more
// propagations waiting.
// Finally, notify the waiting FieldSend thread(s) if (FieldSend.waiting)(
FieldSend.waiting = false;
alerts.notify();
WO 2005/103926
PCT/AU2005/000580
A9. Девятая выборка - это исходный код FieldSend, который распространяет измененные значения, о которых было получено извещение от FieldAlert.
import java.lang.*; import java.lang.reflect.*; import java.util.*; import java.net.*; import java.io.*;
public class FieldSend implements Runnable{
/** Protocol specific values. */
public final static int CLOSE = -1;
public final static int NACK = 0;
public final static int ACK = 1;
public final static int PROPAGATE_OBJECT = 10;
public final static int PROPAGATE_CLASS = 20;
/** FieldAlert network values. */ public final static String group =
System.getProperty("FieldAlert_network_group"); public final static int port =
Integer.parselnt(System.getProperty("FieldAlert_network_port"));
/** Table of global ID'S for local objects. (hashcode-to-globallD mappings) */
public final static Hashtable objectToGloballD = new HashtableO;
/** Table of global ID'S for local classnames. (classname-to-globallD mappings) */
public final static Hashtable classNameToGloballD = new HashtableO;
/** Pending. True if a propagation is pending. */ public static boolean pending = false;
/** Waiting. True if the FieldSend thread(s) are waiting. */ public static boolean waiting = false;
/** Background send thread. Propagates values as this thread is alerted
to their alteration. */ public void run (.) {
System.out.println("FieldAlert_network_group=" + group); System.out.println("FieldAlert_network_port=" + port);
try{
// Create a DatagramSocket to send propagated field values. DatagramSocket datagramSocket =
new DatagramSocket(port, InetAddress.getByName(group));
// Next, create the buffer and packet for all transmissions. byte[] buffer = new byte[512]; // Working limit of 512 bytes
// per packet.
DatagramPacket datagramPacket =
new DatagramPacket(buffer, 0, buffer.length);
while (!Thread.interrupted())(
Object[] entries = null;
// Lock the alerts table, synchronized (FieldAlert.alerts)(
// Await for an alert to propagate something, while (Ipending)(
waiting = true;
FieldAlert.alerts.wait();
WO 2005/103926
PCT/AU2005/000580
waiting = false;
pending = false;
entries = FieldAlert.alerts.entrySet().toArray();
// Clear alerts once we have copied them. FieldAlert.alerts.clear();
// Process each object alert in turn, for (int i=0; Kentries.length; i++){
FieldAlert alert = (FieldAlert) entries[i];
int index = 0;
datagramPacket.setLength(buffer.length);
Object reference = null; if (alert.reference instanceof String); // PROPAGATE_CLASS field operation.
buffer[index++] = (byte) ((PROPAGATE_CLASS " 24) 4 Oxff); buffer[index++] = (byte) ((PROPAGATE_CLASS " 16) s Oxff); buffer[index++] = (byte) ((PROPAGATE_CLASS " 8) 4 Oxff); buffer[index++] = (byte) ((PROPAGATE_CLASS " 0) & Oxff);
String name = (String) alert.reference; int length = name.length();
buffer[index++] = (byte) ((length " 24) & Oxff); buffer[index++] = (byte) ((length " 16) & Oxff); buffer[index++] = (byte) ((length " 8) & Oxff); buffer[index++] = (byte) ((length " 0) & Oxff);
byte[] bytes = name.getBytes();
System.arraycopy(bytes, 0, buffer, index, length); index += length;
}else{ // PROPAGATE_OBJECT field operation.
buffer[index++] =
(byte) ((PROPAGATE_OBJECT " 24) 4 Oxff); buffer[index++] =
(byte) ((PROPAGATE_OBJECT " 16) 4 Oxff); buffer[index++] = (byte) ((PROPAGATE_OBJECT " 8) & Oxff); buffer[index++] = (byte) ((PROPAGATE_OBJECT " 0) 4 Oxff);
int globallD = ((Integer)
objectToGlobalID.get(alert.reference)).intValue();
buffer[index++] = (byte) ((globallD " 24) & Oxff);
buffer [index++] =" (byte) ((globallD " 16) 4 Oxff) ;
buffer[index++] - (byte) ((globallD " 8) 4 Oxff);
buffer[index++] = (byte) ((globallD " 0) 4 Oxff);
reference = alert.reference;
// Use reflection to get a table of fields that correspond to // the field indexes used internally. Field[] fields = null; if (reference == null){
fields = FieldLoader.loadClass((String) alert.reference).getDeclaredFields();
}else{
WO 2005/103926
PCT/AU2005/000580
fields = alert.reference.getClass().getDeclaredFields();
// Now encode in batch mode the fieldlD/value pairs, for (int j=0; j if (alert.fieldAlerts[j] == false) continue;
buffer[index++] = (byte) ((j " 24) & Oxff);
buffer[index++] = (byte) ((j " 16) & Oxff);
buffer[index++] = (byte) ((j " 8) & Oxff);
buffer[index++] = (byte) ((j " 0) & Oxff);
// Encode value.
Class type = fields[j].getType(); if (type == Boolean.TYPE){
buffer[index++] =(byte)
(fields[j].getBoolean(reference)? 1 : 0); Jelse if (type == Byte.TYPE)(
buffer[index++] = fields[j].getByte(reference); }else if (type == Short.TYPE))
short v = fields[j].getShort(reference);
buffer[index++] = (byte) ((v " 8) & Oxff);
buffer[index++] = (byte) ((v > > 0) & Oxff); )else if (type == Character.TYPE)(
char v = fields[j].getChar(reference);
buffer[index++] = (byte) ((v > > 8) & Oxff);
buffer[index++] = (byte) ((v " 0) & Oxff); )else if (type == Integer.TYPE){
int v = fields[j].getlnt(reference);
buffer[index++] = (byte) ((v " 24) & Oxff);
buffer[index++] = (byte) ((v " 16) & Oxff);
buffer[index++] = (byte) ((v " 8) & Oxff);
buffer[index++] = (byte) ((v " 0) & Oxff); }else if (type — Float.TYPE){
int v = Float.floatToIntBits(
fields[j].getFloat(reference) ) ;
buffer[index++] = (byte) ((v " 24) & Oxff);
buffer[index++] = (byte) ((v > > 16) & Oxff); • buffer[index++] = (byte) ((v " 8) & Oxff);
buffer[index++] = (byte) ((v > > 0) & Oxff); }else if (type == Long.TYPE)(
long v " fields[j].getLong(reference) ;
buffer[index++]
= (byte)
( (v
56)
S Oxff)
buffer[index++]
= (byte)
( (v
48)
S Oxff)
buffer[index++]
= (byte)
( (v
40)
S Oxff)
buffer[index++]
= (byte)
( (v
32)
& Oxff)
buffer[index++]
= (byte)
( (v
24)
& Oxff)
buffer[index++]
= (byte)
( (v
1'6)
& Oxff)
buffer[index++]
= (byte)
( (v
& Oxff);
buffer[index++]
- (byte)
( (V
& Oxff);
}else if (type ="- Double.TYPE) (
long v = Double.doubleToLongBits( fields[j].getDouble(reference));
buffer[index++] = (byte) ((v " 56) & Oxff);
buffer[index++] - (byte) ((v " 48) S Oxff);
buffer[index++] = (byte) ((v " 40) & Oxff);
buffer[index++] = (byte) ((v " 32) & Oxff);
buffer[index++] = (byte) ((v " 24) & Oxff);
buffer[index++] " (byte) ((v > > 16) & Oxff);
buffer[index++] - (byte) ((v " 8) & Oxff);
buffer[index++] = (byte) ((v " 0) & Oxff); }else{
throw new AssertionError("Unsupported type.");
WO 2005/103926
PCT/AU2005/000580
// Now set the length of the datagrampacket. datagramPacket.setLength(index);
// Now send the packet. datagramSocket.send(datagramPacket);
}catch (Exception e){
throw new AssertionError("Exception: " + e.toStringO
A10. Десятая выборка - это исходный код FieldReceive, который получает
распространенные измененные значения, отосланные через FieldSend.
import java.lang.*; import java.lang.reflect.*; import java.util.*; import java.net.*; import java.io.*;
public class FieldReceive implements Runnable{
/** Protocol specific values. */
public final static int CLOSE = -1;
public final static int NACK = 0;
public final static int ACK = 1;
public final static int PROPAGATE_OBJECT = 10;
public final static int PROPAGATE_CLASS = 20;
/** FieldAlert network values. */ public final static String group =
System.getProperty("FieldAlert_network_group"); public final static int port =
Integer.parselnt(System.getProperty("FieldAlert_network_port"));
/** Table of global ID'S for local objects. (globallD-to-hashcode mappings) */
public final static Hashtable globallDToObject = new HashtableO;
/** Table of global ID'S for local cl'assnames. (globallD-to-classname mappings) */
public final static Hashtable globallDToClassName = new HashtableO;
/** Called when an application is to acquire a lock. */ public void run(Ц
System.out.println("FieldAlert_network_group=" + group); System.out.println("FieldAlert_network_port=" + port);
try{
// Create a DatagramSocket to send propagated field values from MulticastSocket multicastSocket =¦ new MulticastSocket(port); multicastSocket.joinGroup(InetAddress.getByName(group));
// Next, create the buffer and packet for all transmissions. byte[] buffer = new byte[512]; // Working limit of 512
// bytes per packet.
WO 2005/103926
PCT/AU2005/000580
DatagramPacket datagramPacket =
new DatagramPacket(buffer, 0, buffer.length);
while (IThread.interrupted))){
// Make sure to reset length. datagramPacket.setLength(buffer.length) ;
// Receive the next available packet. multicastSocket.receive(datagramPacket);
int index = 0, length = datagramPacket.getLength();
// Decode the command.
int command = (int) ( ((buffer[index++] & Oxff) " 24) I ((buffer[index++] 4 Oxff) " 16) I ((buffer[index++] 4 Oxff) < < 8) I (buffer[index++] & Oxff));
if (command == PROPAGATE_OBJECT) { // Propagate operation for
// object fields.
// Decode global id.
int globallD = (int) ( ( (buffer[index++] & Oxff) " 24) I ((buffer[index++] & Oxff) " 16) I ((buffer[index++] & Oxff) " 8) I (buffer[index++] & Oxff));
// Now, need to resolve the object in question. Object reference = globallDToObject.get( new Integer(globallD));
// Next, get the array of fields for this object.
Field[] fields = reference.getClass().getDeclaredFields();
while (index < length){
// Decode the field id.
int fieldID = (int) ( ( (buffer[index++] & Oxff) < < 24) I ((buffer[index++] & Oxff) < < 16) . I ((buffer[index++] & Oxff) < < 8) I (buffer[index++] & Oxff));
// Determine value length based on corresponding field // type.
Field field = fields[fieldID]; Class type = field.getType(); if (type — Boolean.TYPE){
boolean v = (buffer[index++] == 1 ? true : false); field.setBoolean(reference, v); }else if (type == Byte.TYPE)( byte v - buffer[index++]; field.setByte(reference, v); }else if (type -= Short.TYPE){
short v =" (short) (( (buffer[index++] & Oxff) " 8)
I (buffer[index++] & Oxff)); field.setShort(reference, v); }else if (type "= Character.TYPE)(
char v - (char) (( (buffer[index++] 4 Oxff) " 8)
I (buffer[index++] & Oxff)); field.setChar(reference, v); }else if (type "- Integer.TYPE){
int v - (int) (((buffer[index++] & Oxff) " 24) I ((buffer[index++] & Oxff) " 16) I ((buffer[index++] 4 Oxff) " 8) I (buffer[index++] 4 Oxff)); field.setlnt(reference, v); }else if (type — Float.TYPE)(
WO 2005/103926
PCT/AU2005/000580
int v = (int) (((buffer[index++] & Oxff) " 24)
I ((buffer[index++] 4 Oxff) " 16)
I ((buffer[index++] 4 Oxff) " 8)
! (buffer[index++] 4 Oxff)); field.setFloat(reference, Float.intBitsToFloat(v) ); }else if (type == Long.TYPE)(
long v = (long) ( ( (buffer[index++] & Oxff) " 56)
I ((buffer[index++] & Oxff) " 48)
I ((buffer[index++] 4 Oxff) " 40)
I ((buffer[index++] s Oxff) < < 32)
I ((buffer[index++] s Oxff) " 24)
I ((buffer[index++] & Oxff) " 16)
I ((buffer[index++] & Oxff) " 8)
I (buffer[index++] & Oxff)); field.setLong(reference, v); }else if (type == Double.TYPE)(
long v = (long) (((buffer[index++] & Oxff) " 56)
I ((buffer[index++] & Oxff) " 48)
I ((buffer[index++] & Oxff) < < 40)
I ((buffer[index++] & Oxff) " 32)
I ((buffer[index++] & Oxff) < < 24)
I ((buffer[index++] & Oxff) " 16)
I ((buffer[index++] & Oxff) " 8)
I (buffer[index++] & Oxff)); field.setDouble(reference, Double.longBitsToDouble (v)); }else{
throw new AssertionError("Unsupported type.");
)else if (command == PROPAGATE_CLASS){ // Propagate an update
// to class fields.
// Decode the classname.
int nameLength = (int) ( ((buffer[index++] & Oxff) < < 24)
I ((buffer[index++] & Oxff) " 16)
I ((buffer[index++] 4 Oxff) " 8)
I (buffer[index++] 4 Oxff)); String name = new String(buffer, index, nameLength); index += nameLength;
// Next, get the array of fields for this class. Field[] fields =
FieldLoader.loadClass(name).getDeclaredFields();
// Decode all batched fields included in this propagation // packet.
while (index < length){ // Decode the field id.
int fieldID = (int) (((buffer[index++] 4 Oxff) < < 24) I ((buffer[index++] 4 Oxff) " 16) I ((buffer[index++] 4 Oxff) " 8) I (buffer[index++] 4 Oxff));
// Determine field type to determine value length. Field field = fields[fieldID]; Class type " field.getType(); if (type ~ Boolean.TYPE)(
boolean v = (buffer[index++] == 1 ? true : false);
field.setBoolean(null, v); }else if (type "- Byte.TYPE)(
byte v = buffer[index++];
field.setByte(null, v); (else if (type — Short.TYPE)(
short v = (short) (((buffer[index++] 4 Oxff) " 8) I (buffer[index++] 4 Oxff));
WO 2005/103926
PCT/AU2005/000580
field.setShort(null, v); }else if (type == Character.TYPE){
char v = (char) ( ( (buffer[index++] & Oxff) " 8) I (buffer[index++] & Oxff));
field.setChar(null, v) ; )else if (type == Integer.TYPE){
int v = (int) ( ( (buffer[index++] & Oxff) " 24) I ((buffer[index++] & Oxff) " 16) I ((buffer[index++] & Oxff) " 8) I (buffer[index++] & Oxff));
field.setlnt(null, v) ; }else if (type == Float.TYPE){
int v = (int) (((buffer[index++] & Oxff) " 24) I ((buffer[index++] & Oxff) " 16) I ((buffer[index++] & Oxff) " 8) I (buffer[index++] & Oxff));
field.setFloat(null, Float.intBitsToFloat(v)); }else if (type == Long.TYPE){
long v = (long) (((buffer[index++] & Oxff) < < 56) I ((buffer[index++] s Oxff) " 48) I ((buffer[index++] & Oxff) " 40) I ((buffer[index++] & Oxff) " 32) I ((buffer[index++] & Oxff) " 24) I ((buffer[index++] & Oxff) " 16) I ((buffer[index++] & Oxff) " 8) I (buffer[index++] & Oxff));
field.setLong(null, v); (else if (type == Double.TYPE)(
long v = (long) ( ( (buffer[index++] & Oxff) < < 56) I ((buffer[index++] 4 Oxff) < < 48) I ((buffer[index++] & Oxff) < < 40) I ((buffer[index++] S Oxff) " 32) I ((buffer[index++] & Oxff) " 24) I ((buffer[index++] 4 Oxff) " 16) I ((buffer[index++] & Oxff) " 8) I (buffer[index++] & Oxff));
field.setDouble(null, Double.longBitsToDouble(v)), }else{ // Unsupported field type.
throw new AssertionError("Unsupported type.");
}catch (Exception e){
throw new AssertionError("Exception: " + e.toString());
All. FieldLoader.java. Эта выборка - исходный код FieldLoader, который модифицирует приложения во время его загрузки.
import java.lang.*; import java.io.*; import java.net.*;
public class FieldLoader extends URLClassLoader(
public FieldLoader(URL[] urls)( super(urls);
WO 2005/103926
PCT/AU2005/000580
protected Class findClass(String name) throws ClassNotFoundException{
ClassFile cf = null;
try{
BufferedlnputStream in =
new BufferedlnputStream(findResource(
name.replace (' . ', 1 / ').concat(".class")).openStream{));
cf = new ClassFile(in);
)catch (Exception e){throw new ClassNotFoundException(e.toString ());}
// Class-wide pointers to the ldc and alert index, int ldcindex = -1; int alertindex = -1;
for (int i=0; i for (int j=0; j if (!(cf.methods[i].attributes[j] instanceof Code_attribute)) continue;
Code_attribute ca = (Code_attribute) cf.methods{i].attributes[j];
boolean changed = false;
for (int z=0; z if ((ca.codetz][0] & Oxff) == 179){ // Opcode for a PUTSTATIC
// instruction.
changed = true;
// The code below only supports fields in this class.
// Thus, first off, check that this field is local to this
// class.
CONSTANT_Fieldref_info fi = (CONSTANT_Fieldref_info)
cf.constant_pool[(int) (((ca.code[z][1] & Oxff) " 8) I ¦ (ca.code[z][2] & Oxff))]; CONSTANT_Class_info ci = (CONSTANT_Class_info)
cf.constant_pool[fi.class_index]; String className "
cf.constant_pool[ci.name_index].toStringO; if (!name.equals(className)){
throw new AssertionError("This code only supports fields " "local to this class");
// Ok, now search for the fields name and index, int index = 0;
CONSTANT_NameAndType_info ni = (CONSTANT_NameAndType_info)
cf.constant_pool[fi.name_and_type_index]; String fieldName =
cf.constant_pool[ni.name_index].toString () ; for (int a=0; a cf.fields[a].name_index].toString(); if (fieldName.equals(fn)){ index = a; break;
// Next, realign the code array, making room for the // insertions.
WO 2005/103926
PCT/AU2005/000580
byte[][] code2 = new byte[ca.code.length+3][] ; System.arraycopy(ca.code, 0, code2, 0, z+1); System.arraycopy(ca.code, z+1, code2, z+4,
ca.code.length-(z+1)); ca.code = code2;
// Next, insert the LDC_W instruction, if (ldcindex == -1)(
CONSTANT_String_info csi =
new CONSTANT_String_info(ci.name_index); cp_info[] cpi = new cp_info[cf.constant_pool.length+1]; System.arraycopy(cf.constant_pool, 0, cpi, 0,
cf.constant_pool.length); cpi[cpi.length - 1] = csi; ldcindex = cpi.length-1; cf.constant_pool = cpi; cf.constant_pool_count++;
ca.code[z+1] = new byte[3]; ca.code[z+l] [0] = (byte) 19;
ca.code[z+1][1] = (byte) ((ldcindex " 8) s Oxff); ca.code[z+1][2] = (byte) (ldcindex & Oxff);
// Next, insert the SIPUSH instruction. ca.code[z+2] = new byte[3]; ca.code[z+2][0] = (byte) 17;
ca.code[z+2][1] = (byte) ((index > > 8) & Oxff); ca.code[z+2][2] = (byte) (index & Oxff);
// Finally, insert the INVOKESTATIC instruction.
if (alertindex == -1)(
// This is the first time this class is encourtering the // alert instruction, so have to add it to the constant // pool.
cp_info[] cpi = new cp_infо[cf.constant_pool.length+6]; System.arraycopy(cf.constant_pool, 0, cpi, 0,
cf.constant_pool.length); cf.constant_pool = cpi; cf.constant_pool_count += 6;
CONSTANT_Utf8_info ul =
new CONSTANTJJtf8_infо("FieldAlert"); cf.constant_pool[cf.constant_pool.length-6] = ul;
CONSTANT_Class_info cl = new CONSTANT_Class_infо(
cf.constant_pool_count-6); cf.constant_pool[cf.constant_pool.length-5] = cl;
ul - new CONSTANT_Utf8_info("alert");
cf,constant_pool[cf.constant_pool.length-4] = ul;
ul = new C0NSTANT_Utf8_info("(Ljava/lang/Object;I)V") ; cf.constant_pocl[cf.constant_pool.length-3] = ul;
CONSTANT_NameAndType_info nl = new CONSTANT_NameAndType_infо(
cf.constant_pool.length-4, cf.constant_pool.length-3); cf.constant_pool[cf.constant_pool.length-2] = nl;
CONSTANT_Methodref_info ml - new CONSTANT_Methodref_infо( cf.constant_pool.length-5, cf.constant_pool.length-2); cf.constant_pool[cf.constant_pool.length-1] = ml; alertindex = cf.constant_pool.length-1;
ca.code[z+3] = new byte[3]; ca.code[z+3][0] = (byte) 184;
ca.code[z+3][1] = (byte) ((alertindex " 8) & Oxff);
WO 2005/103926
PCT/AU2005/000580
ca.code[z+3][2] = (byte) (alertindex & Oxff);
// And lastly, increase the CODE_LENGTH and ATTRIBUTE_LENGTH // values.
ca.code_length += 9;
ca.attribute_length += 9;
// If we changed this method, then increase the stack size by one. if (changed){
ca.max_stack++; // Just to make sure.
try{
ByteArrayOutputStream out = new ByteArrayOutputStream();
cf.serialize(out);
byte[] b = out.toByteArray();
return defineClass(name, b, 0, b.length);
}catch (Exception e)(
throw new ClassNotFoundException(name);
A12. Attributeinfo.java. Домашний класс для представления структур attribute_info в рамках ClassFiles.
import java.lang.*; import java.io.*;
/** This abstract class represents all types of attribute_infо
* that are used in the JVM specifications. *
* All new attribute_infо subclasses are to always inherit from this
* class. */
public abstract class attribute_infо(
public int attribute_name_index; public int attribute_length;
/** This is used by subclasses to register themselves * to their parent ClassFile. */
attribute_info(ClassFile cf){)
/** Used during input serialization by ClassFile only. */ attribute_info(ClassFile cf, DatalnputStream in) throws IOException{
attribute_name_index = in.readChar(); attribute_length = in.readlntO;
WO 2005/103926
PCT/AU2005/000580
/** Used during output serialization by ClassFile only. */ void serialize(DataOutputStream out) throws IOExceptionf
out.writeChar(attribute_name_index); out.writelnt(attribute_length);
/** This class represents an unknown attribute_infо that
* this current version of classfile specification does
* not understand. */
public final static class Unknown extends attribute_infо(
byte[] info;
/** Used during input serialization by ClassFile only. */ Unknown(ClassFile cf, DatalnputStream in)
throws IOException{
super(cf, in);
info = new byte[attribute_length]; in.read(info, 0, attribute_length);
/** Used during output serialization by ClassFile only. */ void serialize(DataOutputStream out) throws IOExceptionf
ByteArrayOutputStream baos = new ByteArrayOutputStream();
super.serialize(out);
out.write(info, 0, attribute_length)
A13. ClassFile.java. Домашний класс для представления структур ClassFile.
import java.lang.*;* import java.io.*; import java.util.*;
/** The ClassFile follows verbatim from the JVM specification. */ public final class ClassFile (
public int magic;
public int minor_version;
public int major_version;
public int constant_pool_count;
public cp_info[] constant_pool;
public int access_flags;
public int this_class;
public int super_class;
public int interfaces_count;
public intf] interfaces;
public int fields_count;
public field_info[] fields;
public int methods_count;
public method_infо[] methods;
public int attributes_count;
public attribute_info[] attributes;
/** Constructor. Takes in a byte stream representation and transforms
* each of the attributes in the ClassFile into objects to allow for
* easier manipulation. */
WO 2005/103926
PCT/AU2005/000580
public ClassFile(InputStream ins) throws IOException{
DatalnputStream in = (ins instanceof DatalnputStream ?
(DatalnputStream) ins : new DatalnputStream(ins)); magic = in.readlnt(); minor_version = in.readChar(); major_version = in.readChar(); constant_pool_count = in.readChar(); constant_pool = new cp_info[constant_pool_count] ; for (int i=l; i in.mark(1);
int s = in.read();
in.reset () ;
switch (s){ case 1:
constant_pool[i] = new CONSTANT_Utf8_info(this, in); break; case 3:
constant_pool[i] = new CONSTANT_Integer_infо(this, in) ; break; case 4 :
constant_pool[i] = new CONSTANT_Float_infо(this, in); break; case 5:
constant_pool[i] = new CONSTANT_Long_info(this, in); i++; break; case 6:
constant_pool[i] = new CONSTANT_Double_infо(this, in); i++; break; case 7 :
constant_pool[i] = new CONSTANT_Class_infо(this, in); break; case 8:
constant_pool[i] = new CONSTANT_String_infо(this, in); break; case 9:
constant_pool[i] = new CONSTANT_Fieldref_infо(this, in); break; case 10:
constant_pool[i] = new CONSTANT_Methodref_infо(this, in);
break; case 11:
constant_pool[i] =
new CONSTANT_InterfaceMethodref_info(this, in);
break; case 12:
constant_pool[i] = new CONSTANT_NameAndType_infо(this, in) break; default:
throw new ClassFormatError("Invalid ConstantPoolTag");
access_flags = in.readChar() ; this_class = in.readChar(); super_class = in.readChar(); interfaces_count = in.readChar(); interfaces " new int[interfaces_count] ; for (int i=0; Kinterfaces_count; i++)
interfaces[i] = in.readChar(); fields_count = in.readChar(); fields =" new field_info[fields_count] ; for (int i=0; i fields[i] = new field_info(this, in) ;
methods_count = in.readChar();
methods " new method info[methods count];
WO 2005/103926
PCT/AU2005/000580
for (int i=0; i methodsfi] = new method_infо(this, in);
attributes_count = in.readChar();
attributes = new attribute_infо[attributes_count]; for (int i=0; i String s = constant_pool[in.readChar()].toString(); in.reset();
if (s.equals("SourceFile"))
attributes[i] = new SourceFile_attribute(this, in); else if (s.equals("Deprecated"))
attributes[i] = new Deprecated_attribute(this, in); else if (s.equals("InnerClasses"))
attributes[i] = new InnerClasses_attribute(this, in);
else
attributes[i] = new attribute_infо.Unknown(this, in);
/** Serializes the ClassFile object into a byte stream. */ public void serialize(OutputStream o) throws IOException(
DataOutputStream out = (o instanceof DataOutputStream ?
(DataOutputStream) о : new DataOutputStream(o)); out.writelnt(magic); out.writeChar(minor_version); out.writeChar(major_version); out.writeChar(constant_pool_count); for (int i=l; i constant_pool[i].serialize(out);
if (constant_pool[i] instanceof CONSTANT_Long_infо ||
constant_pool[i] instanceof CONSTANT_Double_info)
i++;
out.writeChar(access_flags);
out.writeChar(this_class);
out.writeChar(super_class);
out.writeChar(interfaces_count) ;
for (int i=0; i out.writeChar(interfaces[i]); out.writeChar(fields_count); for (int i=0; i fields[i].serialize(out); out.writeChar(methods_count); for (int i=0; i methods[i].serialize(out); out.writeChar(attributes_count); for (int i=0; i attributes[i].serialize(out); // Flush the outputstream just to make sure, out.flush();
A14. Code_attribute.java. Домашний класс для представления структур Code_attribute в рамках ClassFiles.
import java.util.*; import java.lang.*; import java.io.*;
/* *
* The code[] is stored as a 2D array. */ public final class Code_attribute extends attribute_info{
public int max_stack;
WO 2005/103926
PCT/AU2005/000580
public int max_locals;
public int code_length;
public byte[][] code;
public int exception_table_length;
public exception_table[] exception_table;
public int attributes_count;
public attribute_infо[] attributes;
/** Internal class that handles the exception table. */ public final static class exception_table{
public int start_pc;
public int end_pc;
public int handler_pc;
public int catch_type;
/** Constructor called only by method_info. */
Code_attribute(ClassFile cf, int ani, int al, int ms, int ml, int cl, byte[][] cd, int etl, exception_table[] et, int ac, attribute_infо[] a)(
super(cf);
attribute_name_index = ani; attribute_length = al; max_stack = ms; max_locals = ml; code_length = cl; code = cd;
exception_table_length = etl; exception_table = et; attributes_count = ac; attributes = a;
/** Used during input serialization by ClassFile only. */ Code_attribute(ClassFile cf, DatalnputStream in)
throws IOException{
super(cf, in);
max_stack = in.readChar();
max_locals = in.readCharО;
code_length = in.readlnt();
code = new byte[code_length][];
int i = 0;
for (int pos=0; pos case 16:
case 18:
case 21:
case 22:
case 23:
case 24:
case 25:
case 54:
case 55:
case 56:
case 57:
case 58:
case 169:
case 188:
case 196:
code[i] = new byte[2] break;
case 17:
case 19:
case 20:
i++) (
WO 2005/103926
PCT/AU2005/000580
case 132: case 153: case 154: case 155: case 156: case 157: case 158: case 159: case 160: case 161: case 162: case 163: case 164: case 165: case 166: case 167: case 168: case 178: case 179: case 180: case 181: case 182: case 183: case 184: case 187: case 189: case 192: case 193: case 198: case 199: case 209:
codefi] = new byte[3];
break; case 197:
code[i] = new byte[4];
break; case 185: case 200: case 201:
code[i] = new byte[5]; • break; case 170:{
int pad = 3 - (pos % 4);
in.mark(pad+13); // highbyte
in.skipBytes(pad+5); // lowbyte
int low = in.readlnt(); code[i] =
new bytefpad + 13 + ((in.readlnt () - low +1) * 4)]; in.reset(); break; }case 171: {
int pad " 3 - (pos % 4);
in.mark(pad+9);
in.skipBytes(pad+5);
code[i] = new bytefpad + 9 + (in.readlnt() * 8)]; in.reset (); break; Jdefault:
code[i] = new byte[l];
in.read(code[i], 0, code[i].length); pos += code[i].length;
// adjust the array to the new size and store the size byte[][] temp = new byte[i][]; System.arraycopy(code, 0, temp, 0, i); code = temp;
WO 2005/103926
PCT/AU2005/000580
exception_table_length = in.readChar(); exception_table =
new Code_attribute.exception_table[exception_table_length]; for (i=0; i exception_table[i] = new exception_table();
exception_table[i].start_pc = in.readChar() ;
exception_table[i],end_pc = in.readChar();
exception_table[i].handler_pc = in.readChar();
exception_table[i].catch_type = in.readChar() ;
attributes_count = in.readChar();
attributes = new attribute_info[attributes_count]; for (i=0; i String s = cf.constant_pool[in.readChar()].toString(); in.reset () ;
if (s.equals("LineNumberTable"))
attributes[i] = new LineNumberTable_attribute(cf, in); else if (s.equals("LocalVariableTable"))
attributes[i] = new LocalVariableTable_attribute(cf, in);
else
attributes[i] = new attribute_info.Unknown(cf, in);
/** Used during output serialization by ClassFile only. */
void serialize(DataOutputStream out) throws IOException{
attribute_length = 12 + code_length +
(exception_table_length * 8); for (int i=0; i attribute_length += attributes[i].attribute_length + 6; super.serialize(out); out.writeChar(max_stack); out.writeChar(max_locals); out.writelnt(code_length); for (int i=0, pos=0; pos out.write(code[i], 0, code[i].length);
pos. += code [i] . length;
out.writeChar(exception_table_length);
for (int i=0; i out.writeChar(exception_table[i].start_pc);
out.writeChar(exception_table[i].end_pc);
out.writeChar(exception_table[i].handler_pc);
out.writeChar(exception_table[i].catch_type);
out.writeChar(attributes_count); for (int i=0; i A15. CONSTANT_Class_info.java. Домашний класс для представления структур CONSTANT_Class_info в рамках ClassFiles.
import java.lang.*; import java.io.*;
/** Class subtype of a constant pool entry. */
public final class CONSTANT_Class_infо extends cp_info[
/** The index to the name of this class. */
WO 2005/103926
PCT/AU2005/000580
public int name_index = 0;
/** Convenience constructor. */
public CONSTANT_Class_info(int index) { tag = 7;
name_index = index;
/** Used during input serialization by ClassFile only. */ CONSTANT_Class_info(ClassFile cf, DatalnputStream in)
throws IOException{
super(cf, in);
if (tag != 7)
throw new ClassFormatError();
name_index = in.readChar();
/** Used during output serialization by ClassFile only. */ void serialize(DataOutputStream out)
throws IOException{
out.writeByte(tag);
out.writeChar(name_index);
A16. CONSTANT_Double_info.java. Домашний класс для представления структур CONSTANT_Double_info в рамках ClassFiles.
import java.lang.*; import java.io.*;
/** Double subtype of a constant pool entry. */
public final class CONSTANT_Double_infо extends cp_info{
/** The actual value. */ public double bytes;
public CONSTANT_Double_info(double d)( tag = 6; bytes = d;
/** Used during input serialization by ClassFile only. */ CONSTANT_Double_info(ClassFile cf, DatalnputStream in)
throws IOException(
super(cf, in);
if (tag != 6)
throw new ClassFormatError();
bytes = in.readDouble();
/** Used during output serialization by ClassFile only. */ void serialize(DataOutputStream out)
throws IOException(
out.writeByte(tag);
out.writeDouble(bytes);
long 1 = Double.doubleToLongBits(bytes);
A17. CONST ANT_Fieldref.info.java. Домашний класс для представления структур CONSTANTJueldrefjiifo в рамках ClassFiles.
WO 2005/103926
PCT/AU2005/000580
import java.lang.*; import java.io.*;
/** Fieldref subtype of a constant pool entry. */
public final class CONSTANT_Fieldref_infо extends cp_info{
/** The index to the class that this field is referencing to. */ public int class_index;
/** The name and type index this field if referencing to. */ public int name_and_type_index;
/** Convenience constructor. */
public CONSTANT_Fieldref_infо(int class_index, int name_and_type_index) { tag = 9;
this.class_index = class_index;
this.name_and_type_index = name_and_type_index;
/** Used during input serialization by ClassFile only. */ CONSTANT_Fieldref_info(ClassFile cf, DatalnputStream in)
throws IOException(
super(cf, in);
if (tag != 9)
throw new ClassFormatError();
class_index = in.readChar();
name_and_type_index = in.readChar();
/** Used during output serialization by ClassFile only. */ void serialize(DataOutputStream out)
throws IOException{
out.writeByte(tag);
out.writeChar(class_index);
out.writeChar(name_and_type_index);
A18. CONSTANT_Float_info.java. Домашний класс для представления структур CONSTANT_Float_info в рамках ClassFiles.
import java.lang.*; import java.io.*;
/** Float subtype of a constant pool entry. */
public final class CONSTANT_Float_info extends cp_info{
/** The actual value. */ public float bytes;
public CONSTANT_Float_info(float f){ tag = 4; bytes = f;
/** Used during input serialization by ClassFile only. */ CONSTANT_Float_info(ClassFile cf, DatalnputStream in)
throws IOExceptionf
super(cf, in);
if (tag != 4)
throw new ClassFormatError();
bytes =¦ in. readFloat () ;
/** Used during output serialization by ClassFile only. */
WO 2005/103926
PCT/AU2005/000580
public void serialize(DataOutputStream out) throws IOException{ out.writeByte(4) ; out.writeFloat(bytes);
A19. CONST ANT_Integer_info.java. Домашний класс для представления структур CONSTANT_Integer_info в рамках ClassFiles.
import java.lang.*; import java.io.*;
/** Integer subtype of a constant pool entry. */
public final class CONSTANT_Integer_infо extends cp_info{
/** The actual value. */ public int bytes;
public CONSTANT_Integer_info(int b) ( tag = 3; bytes = b;
/** Used during input serialization by ClassFile only. */ CONSTANT_Integer_info(ClassFile cf, DatalnputStream in)
throws IOExceptionf
super(cf, in);
if (tag != 3)
throw new ClassFormatError();
bytes = in.readlnt();
/** Used during output serialization by ClassFile only. */ public void serialize(DataOutputStream out)
throws IOException(
out.writeByte(tag);
out.writelnt(bytes);
A20.CONSTANT_InterfaceMethodref_info.java. Домашний класс для представления структур CONSTANTJnterfaceMemocirefJnfo в рамках класса ClassFiles.
import java.lang.*; import java.io.*;
/** InterfaceMethodref subtype of a constant pool entry. */
public final class C0NSTANT_InterfaceMethodref_infо extends cp_info{
/** The index to the class that this field is referencing to. */ public int class_index;
/** The name and type index this field if referencing to. */ public int name_and_type_index;
public CONSTANT_InterfaceMethodref_info(int class_index,
int name_and_type_index) {
tag - 11;
this.class_index = class_index;
this. name_and_type_index = name_and_type_index;
WO 2005/103926
PCT/AU2005/000580
/** Used during input serialization by ClassFile only. */ CONSTANT_InterfaceMethodref_info(ClassFile cf, DatalnputStream in)
throws IOException{
super(cf, in);
if (tag != 11)
throw new ClassFormatError();
class_index = in.readChar();
name_and_type_index = in.readChar();
/** Used during output serialization by ClassFile only. */ void serialize(DataOutputStream out)
throws IOException{
out.writeByte(tag);
out.writeChar(class_index);
out.writeChar(name_and_type_index) ;
A21. CONSTANT_Long_info.java. Домашний класс для представления структур CONSTANT_Long_info в рамках ClassFiles.
import java.lang.*; import java.io.*;
/** Long subtype of a constant pool entry. */
public final class CONSTANT_Long_info extends cp_info{
/** The actual value. */ public long bytes;
public CONSTANT_Long_info(long b){ tag = 5; bytes = b;
/** Used during input serialization by ClassFile only. */ CONSTANT_Long_infо(ClassFile cf, DatalnputStream in)
throws IOException{
super(cf, in);
if (tag != 5)
throw new ClassFormatError();
bytes = in.readLong() ;
/** Used during output serialization by ClassFile only. */ void serialize(DataOutputStream out)
throws IOException{
out.writeByte(tag);
out.writeLong(bytes);
A22.CONSTANT_Methodref_info.java. Домашний класс для представления структур CONSTANT_Methodref_info в рамках ClassFiles.
import java.lang.*; import j ava.io.*;
WO 2005/103926
PCT/AU2005/000580
/** Methodref subtype of a constant pool entry. */
public final class CONSTANT_Methodref_info extends cp_info{
/** The index to the class that this field is referencing to. */ public int class_index;
/** The name and type index this field if referencing to. */ public int name_and_type_index;
public CONSTANT_Methodref_infо(int class_index, int name_and_type_index) { tag = 10;
this.class_index = class_index;
this.name_and_type_index = name_and_type_index;
/** Used during input serialization by ClassFile only. */ CONSTANT_Methodref_infо(ClassFile cf, DatalnputStream in)
throws IOException(
super(cf, in);
if (tag != 10)
throw new ClassFormatError();
class_index = in.readChar();
name_and_type_index = in.readChar();
/** Used during output serialization by ClassFile only. */ void serialize(DataOutputStream out)
throws IOExceptionl
out.writeByte(tag);
out.writeChar(class_index);
out.writeChar(name_and_type_index);
A23. CONSTANT_NameAndType_info.java. Домашний класс для представления структур CONSTANT_NameAndType_info в рамках ClassFiles.
import java.io.*; import java.lang.*;
/** NameAndType subtype of a constant pool entry. */
public final class CONSTANT_NameAndType_infо extends cp_info{
/** The index to the Utf8 that contains the name. */ public int name_index;
/** The index fo the Utf8 that constains the signature. */ public int descriptor_index;
public CONSTANT_NameAndType_info(int name_index, int descriptor_index) { tag = 12;
this.name_index - name_index; this.descriptor_index = descriptor_index;
/** Used during input serialization by ClassFile only. */ CONSTANT_NameAndType_info(ClassFile cf, DatalnputStream in)
throws IOExceptionf
super(cf, in);
if (tag != 12)
throw new ClassFormatError() ;
name index = in.readChar();
WO 2005/103926
PCT/AU2005/000580
descriptor_index = in.readChar();
/** Used during output serialization by ClassFile only. */ void serialize(DataOutputStream out)
throws IOException{
out.writeByte(tag);
out.writeChar(name_index);
out.writeChar(descriptor_index) ;
A24. CONSTANT_String_info.java. Домашний класс для представления структур CONSTANT_String_info в рамках ClassFiles.
import java.lang.*; import java.io.*;
/** String subtype of a constant pool entry. */
public final class CONSTANT_String_infо extends cp_info{
/** The index to the actual value of the string. */ public int string_index;
public CONSTANT_String_info(int value) ( tag = 8;
string_index = value;
/** ONLY TO BE USED BY CLASSFILE! */
public CONSTANT_String_info(ClassFile cf, DatalnputStream in) throws IOException{ super(cf, in); if (tag != 8)
throw new ClassFormatError(); string_index = in.readChar();
/** Output serialization, ONLY TO BE USED BY CLASSFILE! */ public void serialize(DataOutputStream out)
throws IOException{
out.writeByte(tag);
out.writeChar(string_index);
A25. CONSTANT_Utf8_info.java. Домашний класс для представления структур CONSTANT_Utf8_info в рамках ClassFiles.
import java.io.*; import java.lang.*;
/** Utf8 subtype of a constant pool entry.
* We internally represent the Utf8 info byte array
* as a String. */
public final class CONSTANTJJtf8_info extends cp_info{
/** Length of the byte array. */ public int length;
WO 2005/103926
PCT/AU2005/000580
/** The actual bytes, represented by a String. */ public String bytes;
/** This constructor should be used for the purpose
* of part creation. It does not set the parent
* ClassFile reference. */
public CONSTANT_Utf8_infо(String s) { tag = 1;
length = s.length(); bytes = s;
/** Used during input serialization by ClassFile only. */ public CONSTANT_Utf8_info(ClassFile cf, DatalnputStream in)
throws IOException(
super(cf, in);
if (tag != 1)
throw new ClassFormatError();
length = in.readChar();
byte[] b = new byte[length];
in.read(b, 0, length);
// WARNING: String constructor is deprecated, bytes = new String(b, 0, length);
/** Used during output serialization by ClassFile only. */ public void serialize(DataOutputStream out)
throws IOException{
out.writeByte(tag);
out.writeChar(length);
// WARNING: Handling of String coversion here might be problematic. out.writeBytes(bytes);
public String toString(){ return bytes;
A26. ConstantValueattribute.java. Домашний класс для представления структур ConstantValue_attribute в рамках ClassFiles.
import java.lang.*; import java.io.*;
/** Attribute that allows for initialization of static variables in * classes. This attribute will only reside in a field_info struct. */
public final class ConstantValue_attribute extends attribute_infо( public int constantvalue_index;
public ConstantValue_attribute(ClassFile cf, int ani, int al, int cvi){ super(cf);
attribute_name_index = ani; attribute_length " al; constantvalue index - cvi;
WO 2005/103926
PCT/AU2005/000580
public ConstantValue_attribute(ClassFile cf, DatalnputStream in) throws IOException{ super(cf, in);
constantvalue_index = in.readChar();
public void serialize(DataOutputStream out) throws IOException{ attribute_length = 2; super.serialize(out); out.writeChar(constantvalue_index);
A27. cp_info.java. Домашний класс для представления структур cp_info в рамках ClassFiles.
import java.lang.*; import java.io.*;
/** Represents the common interface of all constant pool parts * that all specific constant pool items must inherit from.
public abstract class cp_info(
/** The type tag that signifies what kind of constant pool
* item it is */ public int tag;
/** Used for serialization of the object back into a bytestream. */ abstract void serialize(DataOutputStream out) throws IOException;
/** Default constructor. Simply does nothing. */ public cp_info() (}
/** Constructor simply takes in the ClassFile as a reference to
* it's parent */
public cp_infо(ClassFile cf) {}
/** Used during input serialization by ClassFile only. */ cp_info(ClassFile cf, DatalnputStream in)
throws IOException{
tag = in.readUnsignedByte();
A28. Deprecatedattribute.java. Домашний класс для представления структур Deprecated_attribute в рамках ClassFiles.
import java.lang.*; import java.io.*;
/** A fix attributed that can be located either in the ClassFile,
* field_info or the method_info attribute. Mark deprecated to
* indicate that the method, class or field has been superceded. */
public final class Deprecated_attribute extends attribute_info(
public Deprecated_attribute(ClassFile cf, int ani, int al)( super(cf);
attribute name index - ani;
WO 2005/103926
PCT/AU2005/000580
attribute length = al;
/** Used during input serialization by ClassFile only. */ Deprecated_attribute(ClassFile cf, DatalnputStream in)
throws IOException(
super(cf, in);
A29. Exceptions_attribute.java. Домашний класс для представления структур Exceptions_attribute в рамках ClassFiles.
import java.lang.*; import java.io.*;
/** This is the struct where the exceptions table are located.
*


* This attribute can only appear once in a method_info struct. */
public final class Exceptions_attribute extends attribute_infо{
public int number_of_exceptions; public int[] exception__index_table;
public Exceptions_attribute(ClassFile cf, int ani, int al, int noe,
int[] eit){
super(cf);
attribute_name_index = ani; attribute_length = al; number_of_exceptions = noe; exception_index_table = eit;
/** Used during input serialization by ClassFile only. */ Exceptions_attribute(ClassFile cf, DatalnputStream in)
throws IOException)
super(cf, in);
number_of_exceptions = in.readChar();
exception_index_table = new int[number_of_exceptions]; for (int i=0; i exception_index_table[i] " in.readChar();
/** Used during output serialization by ClassFile only. */ public void serialize(DataOutputStream out) throws IOException!
attribute_length - 2 + (number_of_exceptions*2); super.serialize(out); out.writeChar(number_of_exceptions); for (int i=0; i A30. field_info.java. Домашний класс для представления структур field_info в рамках ClassFiles.
import java.lang.*; import java.io.*;
/** Represents the field_info structure as specified in the JVM specification.
WO 2005/103926
PCT/AU2005/000580
public final class field_info{
public int access_flags;
public int name_index;
public int descriptor_index;
public int attributes_count;
public attribute_info[] attributes;
/** Convenience constructor. */
public field_info(ClassFile cf, int flags, int ni, int di){ access_flags = flags; name_index = ni; descriptor_index = di; attributes_count = 0; attributes = new attribute_infо[0];
/** Constructor called only during the serialization process.
*


* This is intentionally left as package protected as we
* should not normally call this constructor directly.
*


* Warning: the handling of len is not correct (after String s =...) */
field_info(ClassFile cf, DatalnputStream in) throws IOException! access_flags = in.readChar(); name_index = in.readChar(); descriptor_index = in.readChar(); attributes_count = in.readChar();
attributes = new attribute_infо[attributes_count] ; for (int i=0; i String s = cf.constant_pool[in.readChar()].toString(); in.reset();
if (s.equals("ConstantValue"))
attributes[i] = new ConstantValue_attribute(cf, in); else if (s.equals("Synthetic"))
attributes[i] = new Synthetic_attribute(cf, in); else if. (s.equals("Deprecated"))
attributes[i] = new Deprecated_attribute(cf, in);
else
attributes[i] = new attribute_infо.Unknown(cf, in);
/** To serialize the contents into the output format. */
public void serialize(DataOutputStream out) throws IOException! out.writeChar(access_flags); out.writeChar(name_index); out.writeChar(descriptor_index); out.writeChar(attributes_count); for (int i"0; i A31. InnerClasses_attribute.java. Домашний класс для представления структур InnerClasses_attribute в рамках ClassFiles.
import j ava.lang.*; import java.io.*;
WO 2005/103926
PCT/AU2005/000580
/** A variable length structure that contains information about an
* inner class of this class. */
public final class lnnerClasses_attribute extends attribute_info{
public int number_of_classes; public classes[] classes;
public final static class classes{ int inner_class_info_index; int outer_class_info_index; int inner_name_index; int inner_class_access_flags;
public InnerClasses_attribute(ClassFile cf, int ani, int al,
int noc, classes!] c)(
super(cf);
attribute_name_index = ani; attribute_length = al; number_of_classes = noc;
classes = c; "
/** Used during input serialization by ClassFile only. */ InnerClasses_attribute(ClassFile cf, DatalnputStream in)
throws IOException!
super(cf, in);
number_of_classes = in.readChar();
classes = new InnerClasses_attribute.classes[number_of_classes]; for (int i=0; i classes[i].inner_class_info_index = in.readChar(); classes[i].outer_class_info_index = in.readChar(); classes[i].inner_name_index = in.readChar(); classes[i].inner_class_access_flags = in.readChar();
/** Used during, output serialization by ClassFile only. */ public void serialize(DataOutputStream out) throws IOException!
attribute_length = 2 + (number_of_classes * 8);
super.serialize(out);
out.writeChar(number_of_classes);
for (int i=0; i out.writeChar(classes[i].inner_class_info_index);
out.writeChar(classes[i].outer_class_info_index);
out.writeChar(classes[i].inner_name_index);
out.writeChar(classes[i].inner_class_access_flags);
A32. LineNumberTable_attribute.java. Домашний класс для представления структур LineNumberTable_attribute в рамках ClassFiles.
import java.lang.*; import java.io.*;
/** Determines which line of the binary code relates to the
* corresponding source code. */
public final class LineNumberTable_attribute extends attribute_infо(
WO 2005/103926
PCT/AU2005/000580
public int line_number_table_length;
public line_number_table[] line_number_table;
public final static class line_number_table{ int start_pc; int line_number;
public LineNumberTable_attribute(ClassFile cf, int ani, int al, int lntl,
line_number_table[] Int){
super(cf);
attribute_name_index = ani; attribute_length = al; line_number_table_length = lntl; line_number_table = Int;
/** Used during input serialization by ClassFile only. */ LineNumberTable_attribute(ClassFile cf, DatalnputStream in)
throws IOException{
super(cf, in);
line_number_table_length = in.readChar(); line_number_table = new LineNumberTable_attribute.line_number_table[line_number_table_length]; for (int i=0; i line_number_table[i] = new line_number_table();
line_number_table[i].start_pc = in.readChar();
line_number_table[i].line_number = in.readChar();
/** Used during output serialization by ClassFile only. */ void serialize(DataOutputStream out) throws IOException!
attribute_length = 2 + (line_number_table_length * 4); super.serialize(out);
out.writeChar(line_number_table_length);
for (int i=0; i out.writeChar(line_number_table[i].start_pc);
out.writeChar(line_number_table[i].line_number);
A33. LocalVariableTable_attribute.java. Домашний класс для представления структур LocalVariableTable_attribute в рамках ClassFiles.
import java.lang.*; import java.io.*;
/** Used by debugger to find out how the source file line number is linked
* to the binary code. It has many to one correspondence and is found in
* the Code_attribute. */
public final class LocalVariableTable_attribute extends attribute_info{
public int local_variable_table_length;
public local_variable_table[] local_variable_table;
public final static class local_variable_table{ int start_pc; int length; int name_index; int descriptor_index;
WO 2005/103926
PCT/AU2005/000580
int index;
public LocalVariableTable_attribute(ClassFile cf, int ani, int al,
int lvtl, local_variable_table[] lvt){
super(cf);
attribute_name_index = ani; attribute_length = al; local_variable_table_length = lvtl; local_variable_table = lvt;
/** Used during input serialization by ClassFile only. */ LocalVariableTable_attribute(ClassFile cf, DatalnputStream in)
throws IOException{
super(cf, in);
local_variable_table_length = in.readChar() ; local_variable_table = new LocalVariableTable_attribute.local_variable_table[local_variable_table_length] ; for (int i=0; i local_variable_table[i] = new local_variable_table();
local_variable_table[i].start_pc = in.readChar();
local_variable_table[i].length = in.readChar();
local_variable_table[i].name_index = in.readChar();
local_variable_table[i].descriptor_index = in.readChar();
local_variable_table[i].index = in.readChar();
/** Used during output serialization by ClassFile only. */ • void serialize(DataOutputStream out) throws IOException)
attribute_length = 2 + (local_variable_table_length * 10) ; super.serialize(out);
out.writeChar(local_variable_table_length);
for (int i=0; i out.writeChar(local_variable_table[i].start_pc);
out.writeChar(local_variable_table[i] . length) ;
out.writeChar(local_variable_table[i].name_index);
out.writeChar(local_variable_table[i].descriptor_index);
out.wri.teChar(local_variable_table[i].index);
A34. method info.java. Домашний класс для представления структур method_info в рамках ClassFiles.
import java.lang.*; import java.io.*;
/** This follows the method_info in the JVM specification. */
public final class method_info {
public int access_flags; public int name_index; public int descriptor_index; public int attributes_count; public attribute_info[] attributes;
/** Constructor. Creates a method_info, initializes it with
* the flags set, and the name and descriptor indexes given.
* A new uninitialized code attribute is also created, and stored
* in the code variable.*/
WO 2005/103926
PCT/AU2005/000580
public method_info{ClassFile cf, int flags, int ni, int di, int ac, attribute_infо[] a) { access_flags = flags; name_index = ni; descriptor_index = di; attributes_count = ac; attributes = a;
/** This method creates a method_info from the current pointer in the
* data stream. Only called by during the serialization of a complete
* ClassFile from a bytestream, not normally invoked directly. */
method_info(ClassFile cf, DatalnputStream in) throws IOException{ access_flags = in.readChar(); name_index = in.readChar(); descriptor_index = in.readChar(); attributes_count = in.readChar() ;
attributes = new attribute_infо[attributes_count]; for (int i=0; i String s = cf.constant_pool[in.readChar()].toString();
in.reset();
if (s.equals("Code"))
attributes[i] = new Code_attribute(cf, in); else if (s.equals("Exceptions"))
attributes[i] = new Exceptions_attribute(cf, in); else if (s.equals("Synthetic"))
attributes[i] = new Synthetic_attribute(cf, in); else if (s.equals("Deprecated") )
attributes[i] = new Deprecated_attribute(cf, in);
else
attributes[i] = new attribute_infо.Unknown(cf, in);
/** Output serialization of the method_info to a byte array.
* Not normally invoked directly. */
public void serialize(DataOutputStream out) throws IOException{ out.writeChar(access_flags); out.writeChar(name_index); out.writeChar(descriptor_index); out.writeChar(attributes_count); for (int i=0; i A3 5. SourceFile_attribute.java. Домашний класс для представления структур SourceFile_attribute в рамках ClassFiles.
import java.lang.*; import java.io.*;
/** A SourceFile attribute is an optional fixed_length attribute in
* the attributes table. Only located in the ClassFile struct only
* once. */
public final class SourceFile_attribute extends attribute_info( public int sourcefile_index;
WO 2005/103926
PCT/AU2005/000580
public SourceFile_attribute(ClassFile cf, int ani, int al, int sfi){ super(cf);
attribute_name_index = ani; attribute_length = al; sourcefile_index = sfi;
/** Used during input serialization by ClassFile only. */ SourceFile_attribute(ClassFile cf, DatalnputStream in)
throws IOException!
super(cf, in);
sourcefile_index = in.readChar();
/** Used during output serialization by ClassFile only. */ void serialize(DataOutputStream out)
throws IOException{
attribute_length = 2;
super.serialize(out);
out.writeChar(sourcefile_index);
A36. Synthetic_attribute.java. Домашний класс для представления структур Synthetic_attribute в рамках ClassFiles.
import java.lang.*; import java.io.*;
/** A synthetic attribute indicates that this class does not have
* a generated code source. It is likely to imply that the code
* is generated by machine means rather than coded directly. This
* attribute can appear in the classfile, method_info or field_info.
* It is fixed length. */
public final class Synthetic_attribute extends attribute_infо{
public Synthetic_attribute(ClassFile cf, int ani, int al)( super(cf);
attribute_name_index = ani; attribute length = al;
/** Used during output serialization by ClassFile only. */ Synthetic_attribute(ClassFile cf, DatalnputStream in)
throws IOException{
super(cf, in);
ПРИЛОЖЕНИЕ В
Method 0 new #2
3 dup
4 invokespecial #3 7 putstatic #4 10 return
WO 2005/103926
PCT/AU2005/000580
Method 0 invokestatic #3
3 ifeq 7
6 return
7 new #5 lOdup
11 invokespecial #6
14 putstatic #7
17 return B3
Method
0 aload_0
1 invokespecial #1
4 aload_0
5 invokestatic #2
8 putfield #3 11 return
Method
0 aload_0
1 invokespecial #1
4 invokestatic #2
7 ifeq 11
10 return
11 aload_0
12 invokestatic #4
15 putfield #5
18 return B5
Method 0 ldc #2
2 invokestatic #3
5 ifeq 9
8 return
9 new #5
12 dup
13 invokespecial #6
16 putstatic #7
19 return B6
Method
0 aload_0
1 invokespecial #1
4 aload_0
5 invokestatic #2 8 ifeq 12
11 return
12 aload_0
13 invokestatic #4 16 putfield #5
WO 2005/103926
PCT/AU2005/000580
19 return
ПРИЛОЖЕНИЕ B7 Эта выборка - исходный код InitClient, который запрашивает у "сервера инициализации" инициализационный статус соответствующего класса или объекта.
import java.lang.*; import java.util.*; import java.net.*; import java.io.*;
public class InitClient)
/** Protocol specific values. */
public final static int CLOSE = -1;
public final static int NACK = 0;
public final static int ACK = 1;
public final static int INITIALIZE_CLASS = 10;
public final static int INITIALIZE_OBJECT = 20;
/*.* InitServer network values. */
public final static String serverAddress =
System.getProperty("InitServer_network_address"); public final static int serverPort =
Integer.parseInt(System.getProperty("InitServer_network_port"));
/** Table of global ID's for local objects. (hashcode-to-globallD mappings) */
public final static Hashtable hashCodeToGloballD = new HashtableO;
/** Called when a object is being initialized. */ public static boolean isAlreadyLoaded(Object o){
// First of all, we need to resolve the globallD
// for object 'o'. To do this we use the hashCodeToGloballD
// table.
int globallD =- ((Integer) hashCodeToGloballD.get(o)).intValue(); try{
// Next, we want to connect to the InitServer, which will inform us // of the initialization status of this object. Socket socket = new Socket(serverAddress, serverPort); DataOutputStream out =
new DataOutputStream(socket.getOutputStream()); DatalnputStream in =
new DatalnputStream(socket.getlnputStream());
WO 2005/103926
PCT/AU2005/000580
// Ok, now send the serialized request to the InitServer. out.writelnt(INITIALIZE_OBJECT); out.writelnt(globallD); out.flush();
// Now wait for the reply.
int status = in.readlnt{); // This is a blocking call. So we
// will wait until the remote side // sends something.
if (status == NACK){
throw new AssertionError(
"Negative acknowledgement. Request failed."); }else if (status != ACK)(
throw new AssertionError("Unknown acknowledgement: " + status + ". Request failed.");
// Next, read in a 32bit argument which is the count of previous
// initializations.
int count = in.readlnt();
// If the count is equal to 0, then this is the first // initialization, and hence isAlreadyLoaded should be false. // If however, the count is greater than 0, then this is already // initialized, and thus isAlreadyLoaded should be true, boolean isAlreadyLoaded = (count == 0 ? false : true);
// Close down the connection, out.writelnt(CLOSE); out.flush(); out.closet); in.close();
socket.close(); // Make sure to close the socket.
// Return the value of the isAlreadyLoaded variable, return isAlreadyLoaded;
)catch (IOException e){
throw new AssertionError("Exception: " + e.toString());
/** Called when a class is being initialized. */
WO 2005/103926
PCT/AU2005/000580
public static boolean isAlreadyLoaded(String name){ try{
// First of all, we want to connect to the InitServer, which will // inform us of the initialization status of this class. Socket socket = new Socket(serverAddress, serverPort); DataOutputStream out =
new DataOutputStream(socket.getOutputStream()); DatalnputStream in =
new DatalnputStream(socket.getlnputStream());
// Ok, now send the serialized request to the InitServer. out.writelnt(INITIALIZE_CLASS);
out.writelnt(name.length()) ; // A 32bit length argument of
// the String name.
out.write(name.getBytes(), 0, name.length()); // The byte-
// encoded // String name.
out.flush();
// Now wait for the reply.
int status = in.readlnt(); // This is a blocking call. So we
// will wait until the remote side // sends something.
if (status == NACK){
throw new AssertionError(
"Negative acknowledgement. Request failed."); }else if (status != ACK){
throw new AssertionError("Unknown acknowledgement: " + status + ". Request failed.");
// Next, read in a 32bit argument which is the count of the // previous intializations. int count = in.readlnt();
// If the count is equal to 0, then this is the first
// initialization, and hence isAlreadyLoaded should be false.
// If however, the count is greater than 0, then this is already
// loaded, and thus isAlreadyLoaded should be true.
boolean isAlreadyLoaded = (count == 0 ? false : true);
// Close down the connection, out.writelnt(CLOSE);
WO 2005/103926
PCT/AU2005/000580
out.flush();
out.close () ;
in.close () ;
socket.close () ;
// Make sure to close the socket.
// Return the value of the isAlreadyLoaded variable, return isAlreadyLoaded;
}catch (IOException e){
throw new AssertionError("Exception: it
+ e.toString());
ПРИЛОЖЕНИЕ B8
Данная выборка - это исходный код InitServer, который получает иницилизационный запрос от InitClient и в ответ сообщает соответствующий статус.
import java.lang.*; import java.util.*; import java.net.*; import java.io.*;
public class InitServer implements Runnable{
/** Protocol specific values */
public final static int CLOSE = -1;
public final static int NACK = 0;
public final static int ACK = 1;
public final static int INITIALIZE_CLASS =- 10;
public final static int INITIALIZE_OBJECT= 20;
/** InitServer network values. */
public final static int serverPort = 20001;
/** Table of initialization records. */
public final static Hashtable initializations = new HashtableO;
/** Private input/output objects. */ private Socket socket = null; private DataOutputStream outputStream; private DatalnputStream inputStream; private String address;
public static void main(String[] s) throws Exception!
WO 2005/103926
PCT/AU2005/000580
System.out.println("InitServer_network_address="
+ InetAddress.getLocalHost().getHostAddress()); System.out.println("InitServer_network_port=" + serverPort);
// Create a serversocket to accept incoming initialization operation // connections.
ServerSocket serverSocket = new ServerSocket(serverPort);
while (!Thread.interrupted())(
// Block until an incoming initialization operation connection. Socket socket = serverSocket.accept();
// Create a new instance of InitServer to manage this // initialization operation connection, new Thread(new InitServer(socket)).start() ;
/** Constructor. Initialize this new InitServer instance with necessary
resources for operation. */ public InitServer(Socket s){
socket = s;
try{
outputStream = new DataOutputStream(s.getOutputStream()); inputStream = new DatalnputStream(s.getlnputStream()); address = s.getlnetAddress().getHostAddress(); )catch (IOException e){
throw new AssertionError("Exception: " + e.toString());
/** Main code body. Decode incoming initialization operation requests and
execute accordingly. */ public void run()(
try{
// All commands are implemented as 32bit integers.
// Legal commands are listed in the "protocol specific values"
// fields above.
int command = inputStream.readlnt();
// Continue processing commands until a CLOSE operation, while (command != CLOSE){
WO 2005/103926
PCT/AU2005/000580
if (command == INITIALIZE_CLASS) { // This is an
// INITIALIZE_CLASS // operation.
// Read in a 32bit length field 4', and a String name for
// this class of length 4'.
int length = inputStream.readlnt();
byte[] b = new byte[length];
inputStream.read(b, 0, b.length);
String className = new String(b, 0, length);
// Synchronize on the initializations table in order to // ensure thread-safety, synchronized (initializations)(
// Locate the previous initializations entry for this // class, if any.
Integer entry = (Integer) initializations.get(className);
if (entry == null)( // This is an unknown class so
// update the table with a // corresponding entry.
initializations.put(className, new Integer(1));
// Send a positive acknowledgement to InitClient, • // together with the count of previous initializations // of this class - which in this case of an unknown // class must be 0. outputStream.writelnt(ACK); outputStream.writelnt(0) ; outputStream.flush();
}else{ // This is a known class, so update
// the count of initializations.
initializations.put(className,
new Integer(entry.intValue() + 1));
// Send a positive acknowledgement to InitClient,
// together with the count of previous initializtions
// of this class - which in this case of a known class
// must be the value of "entry.intValue ()".
outputStream.writelnt(ACK) ;
outputStream.writelnt(entry.intValue());
WO 2005/103926
PCT/AU2005/000580
outputStream.flush();
}else if (command == INITIALIZE_OBJECT){ // This is an
// INITIALIZEjDBJECT // operation.
// Read in the globallD of the object to be initialized, int globallD = inputStream.readlnt();
// Synchronize on the initializations table in order to // ensure thread-safety, synchronized (initializations))
// Locate the previous initializations entry for this // object, if any.
Integer entry = (Integer) initializations.get ( new Integer(globallD));
if (entry == null)( // This is an unknown object so
// update the table with a // corresponding entry.
initializations.put(new Integer(globallD), new Integer(1));
// Send a positive acknowledgement to InitClient,
// together with the count of previous initializations
// of this object - which in this case of an unknown
// object must be 0.
outputStream.writelnt(ACK);
outputStream.writelnt(0);
outputStream.flush();
}else{ // This is a known object so update the
// count of initializations.
initializations.put(new Integer(globallD), new Integer(entry.intValue() + 1));
// Send a positive acknowledgement to InitClient,
// together with the count of previous initializations
// of this object - which in this case of a known
WO 2005/103926
PCT/AU2005/000580
// object must be value "entry.intValue()". outputStream.writelnt(ACK); outputStream.writelnt(entry.intValue()); outputStream.flush();
)else{ // Unknown command,
throw new AssertionError(
"Unknown command. Operation failed.");
// Read in the next command, command = inputStream.readlnt() ;
)catch (Exception e){
throw new AssertionError("Exception: " + e.toString()); }finally!
try!
// Closing down. Cleanup this connection. outputStream.flush(); outputStream.close() ; inputStream.close() ; socket . 'close () ; }catch (Throwable t)( t.printStackTrace();
// Garbage these references. outputStream = null; inputStream = null; socket - null;
ПРИЛОЖЕНИЕ B9
Данная выборка - это исходный код примера приложения, которое используется выше/ниже в примерах приложения В.
import java.lang.*;
WO 2005/103926
PCT/AU2005/000580
public class example!
/** Shared static field. */
public static example currentExample;
/** Shared instance field. */ public long timestamp;
/** Static intializer. (clinit) */ static!
currentExample = new example!);
/** Instance intializer (init) */ public example!){
timestamp = System.currentTimeMillis();
ПРИЛОЖЕНИЕ BIO InitLoader.java. Данная выборка - это исходный код InitLoader, который модифицирует приложения во время его загрузки.
import java.lang.*; import java.io.*; import java.net.*;
public class InitLoader extends URLClassLoader(
public InitLoader(URL[] urls){ super(urls);
protected Class findClass(String name) throws ClassNotFoundException!
ClassFile cf = null;
try!
BufferedlnputStream in = new
BufferedlnputStream(findResource(name.replace('.', '/').concat(".class")).openStream());
cf " new ClassFile(in);
}catch (Exception e)(throw new ClassNotFoundException(e.toString());}
for (int i=0; i WO 2005/103926
PCT/AU2005/000580
// Find the method_info struct. String methodName = cf.constant_pool[
cf.methods[i].name_index].toString(); if (ImethodName.equals(" ") ) {
continue;
// Now find the Code_attribute for the method, for (int j=0; j if (!(cf.methods[i].attributes[j] instanceof Code_attribute)) continue;
Code_attribute ca = (Code_attribute) cf.methods[i].attributes[j];
// First, shift the code[] down by 4 instructions. byte[][] code2 = new byte[ca.code.length+4][]; System.arraycopy(ca.code, 0, code2, 4, ca.code.length); ca.code = code2;
// Then enlarge the constant_pool by 7 items. cp_info[] cpi = new cp_infо[cf.constant_pool.length+7]; System.arraycopy(cf.constant_pool, 0, cpi, 0,
cf.constant_pool.length); cf.constant_pool = cpi; cf.constant_pool_count += 7;
// Now add the constant pool items for these instructions, starting // with String.
CONSTANT_String_info csi = new CONSTANT_String_infо(
((CONSTANT_Class_infо)cf.constant_pool[cf.this_class]).name_index); cf.constant_pool[cf.constant_pool.length-7] = csi;
// Now add the UTF for class.
CONSTANT_Utf8_info ul = new CONSTANT_Utf8_infо("InitClient"); cf.constant_pool[cf.constant_pool.length-6] = ul;
// Now add the CLASS for the previous UTF. CONSTANT_Class_info cl =
new CONSTANT_Class_info(cf.constant_pool.length-6); cf.constant_pool[cf.constant_pool.length-5] = cl;
// Next'add the first UTF for NameAndType.
ul = new CONSTANT_Utf8_infо("isAlreadyLoaded");
cf.constant_pool[cf.constant_pool.length-4] = ul;
// Next add the second UTF for NameAndType.
ul - new CONSTANT_Utf8_info("(Ljava/lang/String;)Z");
cf.constant_pool[cf.constant_pool.length-3] = ul;
// Next add the NameAndType for the previous two UTFs. CONSTANT_NameAndType_infо nl = new CONSTANT_NameAndType_infо(
cf.constant_pool.length-4, cf.constant_pool.length-3); cf.constant_pool[cf.constant_pool.length-2] = nl;
// Next add the Methodref for the previous CLASS and NameAndType. CONSTANT_Methodref_info ml - new CONSTANT_Methodref_infо( cf.constant_pool.length-5, cf.constant_pool.length-2); cf.constant_pool[cf.constant_pool.length-1] = ml;
// Now with that done, add the instructions into the code, starting // with LDC.
ca.code[0] = new byte[3]; ca.code[0][0] = (byte) 19;
ca.code[0][1] = (byte) (((cf.constant_pool.length-7) " 8) & Oxff); ca.code[0][2] = (byte) ((cf.constant_pool.length-7) & Oxff);
// Now Add the INVOKESTATIC instruction, ca.codefl] = new byte[3];
WO 2005/103926
PCT/AU2005/000580
ca.code[l][0] = (byte) 184;
ca.codefl] [1] = (byte) (((cf.constant_pool.length-1) > > 8) & Oxff); ca.code[l][2] = (byte) ((cf.constant_pool.length-1) & Oxff);
// Next add the IFEQ instruction.
ca.code[2] = new byte[3];
ca.code[2][0] = (byte) 153;
ca.code[2][1] = (byte) ((4 " 8) & Oxff);
ca.code[2][2] = (byte) (4 & Oxff);
// Finally, add the RETURN instruction. ca.code[3] = new bytefl]; ca.code[3][0] = (byte) 177;
// Lastly, increment the CODE_LENGTH and ATTRIBUTE_LENGTH values.
ca.code_length += 10;
ca.attribute_length += 10;
try{
ByteArrayOutputStream out = new ByteArrayOutputStream(); cf.serialize(out);
byte[] b = out.toByteArray();
return defineClass(name, b, 0, b.length);
}catch (Exception e){ e.printStackTrace () ;
throw new ClassNotFoundException(name);
Приложение С
С1. ТИПИЧНАЯ ФИНАЛИЗАЦИЯ ДЛЯ ОДНОЙ МАШИНЫ, ИЗВЕСТНАЯ ИЗ УРОВНЯ ТЕХНИКИ
Method finalizeO
0 getstatic #9 3 Idc #24
5 mvokevirtual #16 8 return
C2. ПРЕДПОЧТИТЕЛЬНАЯ ФИНАЛИЗ АЦИЯ ДЛЯ МНОЖЕСТВА МАШИН Method finalizeO
0 invokestatic #3 3 ifne 7
6 return
7 getstatic #9 10 Idc #24
12 invokevirtual #16 15 return
WO 2005/103926
PCT/AU2005/000580
СЗ. ПРЕДПОЧТИТЕЛЬНАЯ ФИНАЛИЗАЦИЯ ДЛЯ МНОЖЕСТВА МАШИН (альтернатива)
Method finalizeO
0 aload_0
1 invokestatic #3 4 ifne 8
7 return
8 getstatic #9 11 Idc #24
13 invokevirtual #16 16 return
Приложение C4
import java.lang.*; public class example!
/** Finalize method. */
protected void finalizeO throws Throwablef
// "Deleted..." is printed out when this object is garbaged. System.out.println("Deleted...") ;
import java.lang.*; import java.util.*; import java.net.*; import java.io.*;
public class FinalClientf
/** Protocol specific values. */
public final static int CLOSE = -1;
public final static int NACK = 0;
public final static int ACK = 1;
public final static int FINALI2E_OBJECT - 10;
/** FinalServer network values. */
public final static String serverAddress =
System.getProperty("FinalServer_network_address"); public final static int serverPort -
Integer.parselnt(System.getProperty("FinalServer_network_port"));
/** Table of global ID'S for local objects. (hashcode-to-globallD mappings) */
Приложение С 5
WO 2005/103926
PCT/AU2005/000580
public final static Hashtable hashCodeToGloballD = new HashtableO;
/** Called when a object is being finalized. */ public static boolean isLastReference(Object o){
// First of all, we need to resolve the globallD for object 'o'.
// To do this we use the hashCodeToGloballD table.
int globallD = ((Integer) hashCodeToGloballD.get(o)).intValue();
try{
// Next, we want to connect to the FinalServer, which will inform // us of the finalization status of this object. Socket socket = new Socket(serverAddress, serverPort); DataOutputStream out =
new DataOutputStream(socket.getOutputStream()); DatalnputStream in = new DatalnputStream(socket.getlnputStream());
// Ok, now send the serialized request to the FinalServer. . out.writelnt(FINALIZE_OBJECT); out.writelnt(globallD); out.flush();
// Now wait for the reply.
int status = in.readlnt(); // This is a blocking call. So we
// will wait until the remote side // sends something.
if (status == NACK){
throw new AssertionError;
"Negative acknowledgement. Request failed."); }else if (status != ACK){
throw new AssertionError("Unknown acknowledgement: " + status + ". Request failed.");
// Next, read in a 32bit argument which is the count of the // remaining finalizations int count = in.readlnt();
// If the count is equal to 1, then this is the last finalization, // and hence isLastReference should be true.
// If however, the count is greater than 1, then this is not the // last finalization, and thus isLastReference should be false, boolean isLastReference = (count == 1 ? true : false);
WO 2005/103926
PCT/AU2005/000580
// Close down the connection, out.writelnt(CLOSE); out.flush (); out.close () ; in.close () ;
socket.close(); // Make sure to close the socket.
// Return the value of the isLastReference variable, return isLastReference;
}catch (IOException e){
throw new AssertionError("Exception: " + e.toString());
Приложение С 6
import java.lang.*; import java.util.*; import java.net.*; import java.io.*;
public class FinalServer implements Runnable{
/** Protocol specific values */
public final static int CLOSE = -1;
public final static int NACK = 0;
public final static int ACK = 1;
public final static int FINALIZE_OBJECT = 10;
/** FinalServer network values. */
public final static int serverPort = 20001;
/** Table of finalization records. */
public final static Hashtable finalizations = new HashtableO;
/** Private input/output objects. */ private Socket socket = null; private DataOutputStream outputStream; private DatalnputStream inputStream; private String address;
public static void main(String[] s) throws Exception{
WO 2005/103926
PCT/AU2005/000580
System.out.println("FinalServer_network_address=" + InetAddress.getLocalHost().getHostAddress() ) ; System.out.println("FinalServer_network_port=" + serverPort);
// Create a serversocket to accept incoming initialization operation // connections.
ServerSocket serverSocket = new ServerSocket(serverPort);
while (!Thread.interrupted())(
// Block until an incoming initialization operation connection. Socket socket = serverSocket.accept();
// Create a new instance of InitServer to manage this
// initialization operation connection.
new Thread(new FinalServer(socket)).start();
/** Constructor. Initialize this new FinalServer instance with necessary
resources for operation. */ public FinalServer(Socket s)(
socket =" s;
try(
outputStream = new DataOutputStream(s.getOutputStream()); inputStream = new DatalnputStream(s.getlnputStream()); address = s.getlnetAddress().getHostAddress(); )catch (IOException e)(
throw new AssertionError("Exception: " + e.toString());
/** Main code body. Decode incoming finalization operation requests and
execute accordingly. */ public void run()(
try{
// All commands are implemented as 32bit integers.
// Legal commands are listed in the "protocol specific values"
// fields above.
int command = inputStream.readlnt();
// Continue processing commands until a CLOSE operation.
WO 2005/103926
PCT/AU2005/000580
while (command != CLOSE){
if (command == FINALIZEJDBJECT)( // This is a
// FINALIZE_OBJECT // operation.
// Read in the globallD of the object to be finalized, int globallD = inputStream.readlnt();
// Synchronize on the finalizations table in order to ensure // thread-safety, synchronized (finalizations){
// Locate the previous finalizations entry for this // object, if any.
Integer entry = (Integer) finalizations.get( new Integer(globallD));
if (entry == null)(
throw new AssertionError("Unknown object."); )else if (entry.intValue() < 1){
throw new AssertionError("Invalid count."); }else if (entry.intValue() == 1) ( // Count of 1 means
// this is the last // reference, hence // remove from table.
' finalizations.remove(new Integer(globallD));
// Send a positive acknowledgement to FinalClient, // together with the count of remaining references -// which in this case is 1. outputStream.writelnt(ACK); outputStream.writelnt(1); outputStream.flush();
}else{ // This is not the last remaining
// reference, as count is greater than 1. // Decrement count by 1.
finalizations.put(new Integer(globallD), new Integer(entry.intValue() - 1));
// Send a positive acknowledgement to FinalClient, // together with the count of remaining references to // this object - which in this case of must be value
WO 2005/103926
PCT/AU2005/000580
// "entry.intValueО". outputStream.writelnt(ACK); outputStream.writelnt(entry.intValue()); outputStream.flush();
}else{ // Unknown command,
throw new AssertionError(
"Unknown command. Operation failed.");
// Read in the next command, command = inputStream.readlnt();
}catch (Exception e){
throw new AssertionError("Exception: " + e . toString()); (finally)
try)
// Closing down. Cleanup this connection. outputStream.flush(); outputStream.close (); inputStream.close(); socket.'close () ; }catch (Throwable t){ t.printStackTrace();
// Garbage these references. outputStream = null; inputStream = null; socket = null;
ПРИЛОЖЕНИЕ C7 FinalLoader.java. Данная выборка - это исходный код FinalLoader, который модифицирует приложение во время его загрузки.
import java.lang.*; import java.io.*;
WO 2005/103926
PCT/AU2005/000580
import java.net.*;
public class FinalLoader extends URLClassLoader{
public FinalLoader(URL[] urls)( super(urls);
protected Class findClass(String name) throws ClassNotFoundException(
ClassFile cf = null;
try{
BufferedlnputStream in =
new BufferedlnputStream(findResource(name.replace('.', '/')•concat(".class")).openStream());
cf = new ClassFile(in);
)catch (Exception e){throw new ClassNotFoundException(e.toString());)
for (int i=0; i // Find the finalize method_info struct. String methodName = cf.constant_pool[
cf.methods[i].name_index].toString(); if (!methodName.equals("finalize")){
continue;
// Now find the Code_attribute for the finalize method, for (int j=0; j if (!(cf.methods[i].attributes[j] instanceof Code_attribute)) continue;
Code_attribute ca = (Code_attribute) cf.methods[i] .attributes[j] ;
// First, shift the code[] down by 4 instructions. byte[][] code2 = new byte[ca.code.length+4][]; System.arraycopy(ca.code, 0, code2, 4, ca.code.length); ca.code = code2;
// Then enlarge the constant_pool by 6 items. cp_info[] cpi = new cp_info[cf.constant_pool.length+6]; System.arraycopy(cf.constant_pool, 0, cpi, 0,
cf.constantjpool.length); cf.constant_pool = cpi; cf.constant_pool_count += 6;
// Now add the UTF for class.
CONSTANT_Utf8_info ul = new CONSTANT_Utf8_infо("FinalClient"); cf.constant_pool[cf.constant_pool.length-6] = ul;
// Now add the CLASS for the previous UTF. CONSTANT_Class_info cl =
new CONSTANT_Class_info(cf.constant_pool.length-6); cf.constant_pool[cf.constant_pool.length-5] = cl;
// Next add the first UTF for NameAndType.
ul = new CONSTANT_Utf8_infо("isLastReference") ;
cf.constant_pool[cf.constant_pool.length-4] = ul;
// Next add the second UTF for NameAndType.
ul = new CONSTANT_Utf8_infо("(Ljava/lang/Object;)Z");
cf.constant_pool[cf.constant_pool.length-3] = ul;
// Next add the NameAndType for the previous two UTFs.
WO 2005/103926
PCT/AU2005/000580
CONSTANT_NameAndType_info nl = new CONSTANT_NameAndType_infо(
cf.constant_pool.length-4, cf.constant_pool.length-3); cf.constant_pool[cf.constant_pool.length-2] = nl;
// Next add the Methodref for the previous CLASS and NameAndType. CONSTANT_Methodref_info ml = new CONSTANT_Methodref_infо( cf.constant_pool.length-5, cf.constant_pool.length-2); cf.constant_pool[cf.constant_pool.length-1] = ml;
// Now with that done, add the instructions into the code, starting // with LDC.
ca.code[0] = new byte[l]; ca.code[0][0] = (byte) 42;
// Now Add the INVOKESTATIC instruction. ca.code[l] = new byte[3]; ca.code[1][0] = (byte) 184;
ca.code[1] [1] = (byte) (((cf.constant_pool.length-1) " 8) & Oxff); ca.code[1] [2] = (byte) ((cf.constant_pool.length-1) & Oxff);
// Next add the IFNE instruction.
ca.code[2] = new byte[3];
ca.code[2][0] = (byte) 154;
ca.code[2][1] = (byte) ((4 " 8) & Oxff);
ca.code[2][2] = (byte) (4 & Oxff);
// Finally, add the RETURN instruction. ca.code[3] = new byte[l]; ca.code[3][0] = (byte) 177;
// Lastly, increment the CODE_LENGTH and ATTRIBUTE_LENGTH values.
ca.code_length += 8;
ca.attribute_length += 8;
try(
ByteArrayOutputStream out = new ByteArrayOutputStream(); cf.serialize(out);
byte[] b = out.toByteArray();
return defineClass(name, b, 0, b.length);
}catch (Exception e){ e.printStackTrace();
throw new ClassNotFoundException(name)
Приложение DI
Method void run() 0 getstatic #2
3 dup
4 astore_l
5 monitorenter
6 getstatic #3 9 iconst_l
lOiadd
WO 2005/103926
PCT/AU2005/000580
11 putstatic #3
14 aload_l
15 monitorexit
16 return
Приложение D2
Method void run() 0 getstatic #2
3 dup
4 astore_l
5 dup
6 monitorenter
7 invokestatic #23
10 getstatic #3
13 iconst_l
14 iadd
15 putstatic #3 18aload_l
19 dup
20 invokestatic #24
23 monitorexit
24 return
Приложение D3
import java.lang.*; public class example!
/** Shared static field. */
public final static Object LOCK = new Object!);
/** Shared static field. */ public static int counter = 0;
/** Example method using synchronization. This method serves to
illustrate the use of synchronization to implement thread-safe modification of a shared memory location by potentially multiple threads. */
public void run(){
// First acquire the lock, otherwise any memory writes we do will be // prone to race-conditions, synchronized (LOCK)(
// Now that we have acquired the lock, we can safely modify memory
// in a thread-safe manner.
counter++;
WO 2005/103926
PCT/AU2005/000580
Приложение D4
import java.lang.*;
import java.util.*;
import java.net.*;
import java.io.*;
public class LockClient(
/** Protocol specific values. */
public final static int CLOSE = -1;
public final static int NACK = 0;
public final static int ACK = 1;
public final static int ACQUIRE_LOCK = 10;
public final static int RELEASE_LOCK = 20;
/** LockServer network values. */
public final static String serverAddress =
System.getProperty("LockServer_network_address"); public final static int serverPort =
Integer.parselnt(System.getProperty("LockServer_network_port"));
/** Table of global ID'S for local objects. (hashcode-to-globallD mappings) */
public final sta.tic Hashtable hashCodeToGloballD = new HashtableO;
/** Called when an application is to acquire a lock. */ public static void acquireLock(Object o){
// First of all, we need to resolve the globallD for object 'o'.
// To do this we use the hashCodeToGloballD table.
int globallD " ((Integer) hashCodeToGloballD.get(o)).intValue();
try{
// Next, we want to connect to the LockServer, which will grant us // the global lock.
Socket socket = new Socket(serverAddress, serverPort); DataOutputStream out =
new DataOutputStream(socket.getOutputStream()); DatalnputStream in = new DatalnputStream(socket.getlnputStream());
// Ok, now send the serialized request to the lock server.
WO 2005/103926
PCT/AU2005/000580
out.writelnt(ACQUIRE_LOCK); out.writelnt(globallD); out.flush();
// Now wait for the reply.
int status = in.readlnt(); // This is a blocking call. So we
// will wait until the remote side // sends something.
if (status == NACK)(
throw new AssertionError(
"Negative acknowledgement. Request failed."); }else if (status != ACK){
throw new AssertionError("Unknown acknowledgement: " + status + ". Request failed.");
// Close down the connection, out.writelnt(CLOSE); out.flush(); out.close () ; in.close () ;
socket.close(); // Make sure to close the socket.
// This is a good acknowledgement, thus we can return now because
// global lock is now acquired.
return;
}catch (IOException e){
throw new AssertionError("Exception: " + e.toString ());
/** Called when an application is to release a lock. */ public static void releaseLock(Object o){
// First of all, we need to resolve the globallD for object 'o'.
// To do this we use the hashCodeToGloballD table.
int globallD = ((Integer) hashCodeToGloballD.get(o)).intValue();
try(
// Next, we want to connect to the LockServer, which records us as // the owner of the global lock for object 'o'.
WO 2005/103926
PCT/AU2005/000580
Socket socket = new Socket(serverAddress, serverPort); DataOutputStream out =
new DataOutputStream(socket.getOutputStream()); DatalnputStream in = new DatalnputStream(socket.getlnputStream());
// Ok, now send the serialized request to the lock server, out.writelnt(RELEASE_LOCK) ; out.writelnt(globallD) ; out.flush();
// Now wait for the reply.
int status = in.readlnt(); // This is a blocking call. So we
// will wait until the remote side // sends something.
if (status == NACK){
throw new AssertionError(
"Negative acknowledgement. Request failed."); )else if (status != ACK)(
throw new AssertionError("Unknown acknowledgement: " + status + ". Request failed.");
// Close down the connection, out.writelnt(CLOSE); out.flush (); out.close(); in.close ()';
socket.close() ; // Make sure to close the socket.
// This is a good acknowledgement, return because global lock is
// now released.
return;
}catch (IOException e)(
throw new AssertionError("Exception: " + e.toString());
Приложение D5
import java.lang.*;
WO 2005/103926
PCT/AU2005/000580
import java.util.*; import java.net.*; import java.io.*;
public class LockServer implements Runnable{
/** Protocol specific values */
public final static int CLOSE = -1;
public final static int NACK = 0;
public final static int ACK = 1;
public final static int ACQUIRE_LOCK = 10;
public final static int RELEASE_LOCK = 20;
/** LockServer network values. */
public final static int serverPort = 20001;
/** Table of lock records. */
public final static Hashtable locks = new HashtableO;
/** Linked list of waiting LockManager objects. */ public LockServer next = null;
/** Address of remote LockClient. */ public final String address;
/** Private input/output objects. */ private Socket socket = null; private DataOutputStream outputStream; private DatalnputStream inputStream;
public static void main(String[] s) throws Exception)
System.out.println("LockServer_network_address="
+ InetAddress.getLocalHost().getHostAddress()); System.out.println("LockServer_network_port=" + serverPort);
// Create a serversocket to accept incoming lock operation // connections.
ServerSocket serverSocket = new ServerSocket(serverPort);
while (!Thread.interrupted()){
// Block until an incoming lock operation connection. Socket socket = serverSocket.accept();
WO 2005/103926
100
PCT/AU2005/000580
// Create a new instance of LockServer to manage this lock // operation connection.
new Thread(new LockServer(socket)).start();
/** Constructor. Initialise this new LockServer instance with necessary
resources for operation. */ public LockServer(Socket s)(
socket = s;
try{
outputStream = new DataOutputStream(s.getOutputStream()); inputStream = new DatalnputStream(s.getlnputStream()); address = s. getlnetAddress().getHostAddressО; }catch (IOException e)(
throw new AssertionError("Exception: " + e.toString ()) ;
/** Main code body. Decode incoming lock operation requests and execute
accordingly. */ public void run(){
try(
// All commands are implemented as 32bit integers.
// Legal commands are listed in the "protocol specific values"
// fields above.
int command = inputStream.readlnt();
II Continue processing commands until a CLOSE operation, while (command != CLOSE)(
if (command ==" ACQUIRE_LOCK) ( // This is an
// ACQOIRE_LOCK // operation.
// Read in the globallD of the object to be locked, int globallD = inputStream.readlntО;
// Synchronize on the locks table in order to ensure thread-// safety.
synchronized (locks){
WO 2005/103926
101
PCT/AU2005/000580
// Check for an existing owner of this lock. LockServer lock = (LockServer) locks.get(
new Integer(globallD));
if (lock == null){ // No-one presently owns this lock, // so acquire it.
locks.put(new Integer(globallD), this);
acquireLock();
// Signal to the client the
// successful acquisition of this
// lock.
}else{ // Already owned. Append ourselves //to end of queue.
// Search for the end of the queue. (Implemented as // linked-list) while (lock.next != null){ lock = lock.next;
lock.next = this; // Append this lock request at end.
// Read in the globallD of the object to be locked, int globallD = inputStream.readlnt();
// Synchronize on the locks table in order to ensure thread-// safety.
synchronized (locks){
// Check to make sure we are the owner of this lock. LockServer lock = (LockServer) locks.get( new Integer(globallD));
if (lock == null)(
throw new AssertionError("Unlocked. Release failed."); }else if (lock.address != this.address){
throw new AssertionError("Trying to release a lock "
}else i'f (command == RELEASE LOCK) { // This is a
// RELEASE LOCK
// operation.
WO 2005/103926
102
PCT/AU2005/000580
+ "which this client doesn't own. Release " + "failed.");
lock = lock.next;
lock.acquireLock(); // Signal to the client the
// successful acquisition of this // lock.
// Shift the linked list of pending acquisitions forward // by one.
locks.put(new Integer(globallD), lock);
// Clear stale reference, next = null;
releaseLock(); // Signal to the client the successful // release of this lock.
)else( // Unknown command,
throw new AssertionError(
"Unknown command. Operation failed.");
// Read in the next command, command = inputStream.readlnt();
}catch (Exception e)(
throw new AssertionError("Exception: " + e.toString ()); )finally{
try{
// Closing down. Cleanup this connection. outputStream.flush(); outputStream.close(); inputStream.close(); socket.close(); )catch (Throwable t){ t.printStackTrace();
// Garbage these references. outputStream = null; inputStream = null; socket = null;
WO 2005/103926
103
PCT/AU2005/000580
/** Send a positive acknowledgement of an ACQUIRE_LOCK operation. */ public void acquireLock() throws IOException!
outputStream.writelnt(ACK);
outputStream.flush();
/** Send a positive acknowledgement of a RELEASE_LOCK operation. */ public void releaseLock() throws IOException)
outputStream.writelnt(ACK);
outputStream.flush();
ПРИЛОЖЕНИЕ D6
LockLoader.java. Данная выборка - это исходный код LockLoader, который модифицирует приложение во время его загрузки.
import java.lang.*; import java.io.*; import java.net.*;
public class LockLoader extends URLClassLoader{
public LockLoader(URL[] urls){ super(urls); •
protected Class findClass(String name) throws ClassNotFoundException!
ClassFile cf = null;
try!
BufferedlnputStream in =
new BufferedlnputStream(findResource(name.replace('.', '/').concat (".class")).openStream());
cf - new ClassFile(in);
}catch (Exception e)(throw new ClassNotFoundException(e.toString());}
// Class-wide pointers to the enterindex and exitindex. int enterindex = -1; int exitindex = -1;
for (int i=0; i for (int j=0; j if (!(cf.methods[i].attributes[j] instanceof Code_attribute)) continue;
Code attribute ca =• (Code attribute) cf.methods[i].attributes[j];
WO 2005/103926
104
PCT/AU2005/000580
boolean changed = false;
for (int z=0; z if ((ca.codefz][0] & Oxff) == 194)( // Opcode for a
// MONITORENTER // instruction.
changed = true;
// Next, realign the code array, making room for the // insertions.
byte[][] code2 = new byte[ca.code.length+2][]; System.arraycopy(ca.code, 0, code2, 0, z); code2[z+l] = ca.code[z];
System.arraycopy(ca.code, z+1, code2, z+3,
ca.code.length-(z+1)); ca.code = code2;
// Next, insert the DUP instruction, ca.codefz] = new byte[l]; ca.code[z][0] = (byte) 89;
// Finally, insert the INVOKESTATIC instruction.
if (enterindex == -1){
// This is the first time this class is encourtering the // acquirelock instruction, so have to add it to the // constant pool.
cp_info[] cpi = new cp_infо[cf.constant_pool.length+6]; System.arraycopy(cf.constant_pool, 0, cpi, 0,
cf.constant_pool.length) ; cf.constant_pool = cpi; cf.constant_pool_count += 6;
CONSTANT_Utf8_info ul =
new CONSTANT_Utf8_info("LockClient"); cf.constant_pool[cf.constant_pool.length-6] * ul;
CONSTANT_Class_info cl = new CONSTANT_Class_infо(
cf.constant_pool_count-6); cf.constant_pool[cf.constant_pool.length-5] = cl;
ul = new CONSTANT_Utf8_info("acquireLock"); cf.constant_pool[cf.constant_pool.length-4] = ul;
ul = new CONSTANT_Utf8_info("(Ljava/lang/Object;)V"); cf.constant_pool[cf.constant_pool.length-3] " ul;
CONSTANT_NameAndType_info nl = new CONSTANT_NameAndType_infot
cf.constant_pool.length-4, cf.constant_pool.length-3); cf.constant_pool[cf.constant_pool.length-2] " nl;
CONSTANT_Methodref_info ml - new CONSTANT_Methodref_info( cf.constant_pool.length-5, cf.constant_pool.length-2); cf.constant_pool[cf.constant_pool.length-1] = ml; enterindex " cf.constant_pool.length-1;
ca.code[z+2] " new byte[3]; ca.code[z+2][0] = (byte) 184;
ca.code[z+2][1] = (byte) ((enterindex " 8) & Oxff); ca.code[z+2][2] = (byte) (enterindex & Oxff);
// And lastly, increase the CODE_LENGTH and ATTRIBUTE_LENGTH // values.
ca.code_length += 4;
ca.attribute_length += 4;
WO 2005/103926
105
PCT/AU2005/000580
z += 1;
}else if ((ca.code[z][0] s Oxff) == 195){ // Opcode for a
// MONITOREXIT // instruction.
changed = true;
// Next, realign the code array, making room for the // insertions.
byte[][] code2 = new byte[ca.code.length+2][]; System.arraycopy(ca.code, 0, code2, 0, z); code2[z+l] = ca.code[z];
System.arraycopy(ca.code, z+1, code2, z+3,
ca.code.length-(z+1)); ca.code = code2;
// Next, insert the DUP instruction. ca.code[z] = new byte[l]; ca.codefz][0] = (byte) 89;
// Finally, insert the INVOKESTATIC instruction.
if (exitindex == -1)(
// This is the first time this class is encourtering the // acquirelock instruction, so have to add it to the // constant pool.
cp_info[] cpi = new cp_infо[cf.constant_pool.length+6]; System.arraycopy(cf.constant_pool, 0, cpi, 0,
cf.constant_pool.length); cf.constant_pool = cpi; cf.constant_pool_count += 6;
CONSTANT_Utf8_info ul =
new CONSTANT_Utf8_info("LockClient"); cf.constant_pool[cf.constant_pool.length-6] = ul;
CONSTANT_Class_info cl = new CONSTANT_Class_infо(
cf.constant_pool_count-6); cf.constant_pool[cf.constant_pool.length-5] = cl;
ul =" new CONSTANT_Utf8_info("releaseLock"); . cf.constant_pool[cf.constant_pool.length-4] = ul;
ul = new CONSTANT_Utf8_info("(Ljava/lang/Object;)V"); cf.constant_pool[cf.constant_pool.length-3] = ul;
CONSTANT_NameAndType_info nl = new CONSTANT_NameAndType_infо(
cf.constant_pool.length-4, cf.constant_pool.length-3); cf.constant_pool[cf.constant_pool.length-2] = nl;
CONSTANT_Methodref_info ml - new CONSTANT_Methodref_infо( cf.constant_pool.length-5, cf.constant_pool.length-2); cf.constant_pool[cf.constant_pool.length-1] " ml; exitindex = cf.constant_pool.length-1;
ca.code[z+2] = new byte[3]; ca.code[z+2][0] = (byte) 184;
ca.code[z+2][1] = (byte) ((exitindex " 8) & Oxff); ca.code[z+2][2] = (byte) (exitindex & Oxff);
// And lastly, increase the CODE_LENGTH and ATTRIBUTE_LENGTH // values.
ca.code_length += 4;
ca.attribute_length += 4;
z +=" 1;
WO 2005/103926
106
PCT/AU2005/000580
// If we changed this method, then increase the stack size by one. if (changed)(
ca.max_stack++; // Just to make sure.
try{
ByteArrayOutputStream out = new ByteArrayOutputStream(); cf.serialize(out);
byte[] b = out.toByteArray();
return defineClass(name, b, 0, b.length);
}catch (Exception e){
throw new ClassNotFoundException(name);
WO 2005/103926
PCT/AU2005/000580
ФОРМУЛА ИЗОБРЕТЕНИЯ
1. Многокомпьютерная система, имеющая по меньшей мере одно приложение, запущенное одновременно на множестве объединенных сетью связи компьютеров, в которой создано однородное множество идентичных по существу объектов, каждый из которых создается на соответствующем компьютере и имеет идентичное по существу имя, причем начальное содержание каждого из указанных идентично поименованных объектов является одинаковым, при этом все указанные идентичные объекты одновременно удаляются, если каждый из указанного множества компьютеров более не нуждается в обращении к их соответствующему объекту, при этом данная система включает в себя средство блокировки, применимое ко всем указанным компьютерам, причем любой компьютер, намеревающийся использовать некий поименованный объект на нем, получает авторизационный блокиратор из указанного средства блокировки, который разрешает это использование и предотвращает использование всеми другими компьютерами их соответствующего поименованного объекта до тех пор, пока этот блокиратор не будет снят.
2. Система по п.1, в которой указанное средство блокировки содержит подпрограмму получения блокиратора и подпрограмму освобождения блокиратора, и обе эти подпрограммы включены в модификации, вносимые в указанную программу приложения, выполняемую на всех указанных компьютерах.
3. Система по п.2, в которой указанное средство блокировки также содержит общую таблицу, в которой перечислены указанные поименованные объекты, используемые любым из указанных компьютеров, статус блокиратора каждого указанного объекта и очередь любых ждущих получений блокиратора.
4. Система по п.З, в которой указанное средство блокировки находится на дополнительном компьютере, на котором указанная программа приложения не выполняется, но который подключен к указанной сети связи.
5. Система по п.1, в которой каждый из указанных компьютеров содержит распределенные средства выполнения, которые могут взаимодействовать со всеми другими компьютерами, при этом если часть указанной по меньшей мере одной программы приложения, выполняемая на одном из указанных компьютеров, создает объект на этом компьютере, то этот созданный объект распространяется
WO 2005/103926
PCT/AU2005/000580
распределенными средствами выполнения указанного одного компьютера на все другие компьютеры.
6. Система по п.1, в которой каждый из указанных компьютеров содержит распределенные средства выполнения, которые могут взаимодействовать со всеми другими компьютерами, при этом, если часть указанной по меньшей мере одной программы приложения, выполняемая на одном из указанных компьютеров, более не нуждается в обращении к объекту на этом компьютере, то идентификатор этого объекта без ссылки передается распределенными средствами выполнения указанного одного компьютера в общую таблицу, доступную для всех других компьютеров.
7. Система по п.1, в которой каждая указанная программа приложения модифицируется до, во время или после загрузки путем вставки подпрограммы инициализации для модификации каждого экземпляра объекта при создании этого объекта указанной программой приложения, причем указанная подпрограмма инициализации распространяет каждый объект, заново созданный одним компьютером, на все указанные другие компьютеры.
8. Система по п.7, в которой программа приложения модифицируется в соответствии с процедурой, выбранной из группы процедур, состоящих из рекомпиляции во время загрузки, прекомпиляции до загрузки, компиляции до загрузки, динамической компиляции и рекомпиляции после загрузки, но до выполнения соответствующей части программы приложения.
9. Система по п.7, в которой указанная модифицированная программа приложения передается на все указанные компьютеры в соответствии с процедурой, выбранной из группы, состоящей из передачи типа "ведущий/ведомый", ветвеобразной передачи и каскадной передачи.
10. Система по п.1, в которой емкость локальной памяти, выделенная указанной или каждой программе приложения, по существу идентична, а общая емкость памяти, доступная для указанной или каждой программы приложения, представляет собой указанную выделенную емкость памяти.
11. Система по п. 10, в которой все указанные компьютеры содержат средство распределения обновлений, каждое из которых взаимодействует через указанный канал связи на скорости передачи данных, которая существенно меньше скорости считывания локальной памяти.
WO 2005/103926
PCT/AU2005/000580
12. Система по п.П, в которой по меньшей мере некоторые из указанных компьютеров произведены различными производителями и/или имеют различные операционные системы.
13. Способ одновременного выполнения по меньшей мере одной программы приложения на множестве компьютеров, соединенных посредством сети связи, включающий следующие шаги:
(i) создание однородного множества идентичных по существу объектов, каждый из которых расположен на соответствующем компьютере и имеет по существу идентичное другим имя,
(и) создание идентичного по существу начального содержания каждого из указанных идентично поименованных объектов,
(ш) одновременное удаление всех указанных идентичных объектов, если все из указанного множества компьютеров более не нуждаются в обращении к своему соответствующему объекту,
(iv) запрос каждым указанным компьютером, намеревающимся использовать некий поименованный объект на нем, авторизационного блокиратора, который разрешает указанное использование и предотвращает использование всеми другими компьютерами их соответствующих поименованных объектов до тех пор, пока указанный блокиратор не будет освобожден.
14. Способ по п. 13, содержащий дополнительный шаг:
(v) если часть указанной программы приложения, выполняемая на одном из указанных компьютеров, создает объект на этом компьютере, то созданный объект распространяется на все другие компьютеры через указанную сеть связи.
15. Способ по п. 14, содержащий дополнительный шаг:
(vi) модификация указанной программы приложения до, во время или после загрузки путем вставки подпрограммы инициализации для модификации каждого экземпляра объекта при создании этого объекта указанной программой приложения, при этом указанная подпрограмма инициализации распространяет каждый объект, созданный одним компьютером, на все другие указанные компьютеры.
16. Способ по п. 13, содержащий дополнительный шаг:
(vii) обеспечение каждого указанного компьютера распределенными средствами выполнения для взаимодействия указанных компьютеров через указанную сеть связи.
WO 2005/103926
PCT/AU2005/000580
17. Способ по п. 16, содержащий дополнительный шаг:
(viii) обеспечение общей таблицы, доступной каждому из указанных распределенных средств выполнения, в которой хранится идентификатор любого компьютера, который более не нуждается в доступе к какому-либо объекту, вместе с идентификатором этого объекта.
18. Способ по п. 17, содержащий дополнительный шаг:
(ix) ассоциирование средства подсчета с указанной общей таблицей, причем указанное средство подсчета хранит подсчитанное число указанных компьютеров, которые более не требуют доступа к указанному объекту.
19. Способ по п. 18, содержащий дополнительный шаг:
(x) обеспечение дополнительного компьютера, на котором указанная общая программа не выполняется, но который является ведущим узлом для указанной общей таблицы и счетчика, причем указанный дополнительный компьютер подсоединен к указанной сети связи.
20. Способ по п. 16, содержащий дополнительный шаг:
(xi) обеспечение общей таблицы, доступной каждому из указанных распределенных средств выполнения, в которой хранится идентификатор любого компьютера, который в текущий момент должен получить доступ к какому-либо объекту, вместе с идентификатором этого объекта.
21. Способ по п. 20, содержащий дополнительный шаг:
(ix) ассоциирование средства подсчета с указанной общей таблицей, причем указанное средство подсчета хранит подсчитанное число указанных компьютеров, которые запрашивают доступ к указанному объекту.
22. Способ по п. 21, содержащий дополнительный шаг:
(xiii) обеспечение дополнительного компьютера, на котором указанная общая программа не выполняется, но который является ведущим узлом для указанной общей таблицы и счетчика, причем указанный дополнительный компьютер подсоединен к указанной сети связи.
23. Компьютерный программный продукт, содержащий набор программных команд, который находится на носителе информации и может быть запущен на выполнение с обеспечением реализации на множестве компьютеров способа по п. 13.
WO 2005/103926
PCT/AU2005/000580
24. Множество компьютеров, соединенных сетью связи и обеспечивающих согласованную инициализацию программы приложения, выполняемой на указанных компьютерах одновременно, причем указанные компьютеры запрограммированы для реализации способа по п. 13 или на них загружен компьютерный программный продукт по п.23.
1/24
ЗАПОМИНАЮЩЕЕ УСТРОЙСТВО
ФИ Г Л
УРОВЕНЬ ТЕХНИКИ
ЦП1
ЦП2
ГЛОБАЛЬНАЯ ПАМЯТЬ
ФИГ.2
УРОВЕНЬ ТЕХНИКИ
1/пАр
ФИГ.З
УРОВЕНЬ ТЕХНИКИ
1/пАр
2/24
ФИ Г. 4
УРОВЕНЬ ТЕХНИКИ
КОД + ДАННЫЕ
ВИРТУАЛЬНАЯ JAVA-МАШИНА
ФИГ. 6
УРОВЕНЬ ТЕХНИКИ
- 61
КОД + ДАННЫЕ
*->
РАСПРЕДЕЛЕННОЕ ИСПОЛНЕНИЕ ПРОГРАММЫ
50----^
ЗАГРУЗКА V_?1
ВИРТУАЛЬНАЯ JAVA-МАШИНА
72-^
ФИГ.7
71/2
71/п
код +
D.R.T.
ДАННЫЕ
IV) 4-х
4/24
СОЗДАНИЕ СПИСКА ВСЕХ АДРЕСОВ ПАМЯТИ (Т.Е. ПОЛЯ КЛАССОВ И ОБЪЕКТОВ НА ЯЗЫКЕ JAVA)
ПОИСК В ИСПОЛНЯЕМОМ КОДЕ ДЛЯ ОБНАРУЖЕНИЯ ЗАПИСИ ПО КАКОМУ-ЛИБО АДРЕСУ ПАМЯТИ ИЗ СПИСКА
ВСТАВКА "ПОДПРОГРАММЫ РАСПРОСТРАНЕНИЯ ОБНОВЛЕНИЙ", ЧТОБЫ (1) РАСПРОСТРАНИТЬ ИДЕНТИФИКАТОР УКАЗАННЫХ В СПИСКЕ АДРЕСОВ ПАМЯТИ НА ВСЕ ДРУГИЕ МАШИНЫ И (2) ИЗВЕСТИТЬ ВСЕ ДРУГИЕ МАШИНЫ О ЛЮБОМ ИЗМЕНЕНИИ ЗНАЧЕНИЯ ЛЮБОГО АДРЕСА ПАМЯТИ ИЗ СПИСКА
ПРОДОЛЖЕНИЕ ПРОЦЕДУРЫ ЗАГРУЗКИ
.. . _|_.
ФИГ.9
5/24
СОЗДАНИЕ СПИСКА ВСЕХ АДРЕСОВ ПАМЯТИ (Т.Е. ПОЛЯ КЛАССОВ И ОБЪЕКТОВ НА ЯЗЫКЕ JAVA)
ПОИСК В ИСПОЛНЯЕМОМ КОДЕ ДЛЯ ОБНАРУЖЕНИЯ ЗАПИСИ ПО КАКОМУ-ЛИБО АДРЕСУ ПАМЯТИ ИЗ СПИСКА
ВСТАВКА "ПОДПРОГРАММЫ ПРЕДУПРЕЖДЕНИЯ", ЧТОБЫ ДАТЬ КОМАНДУ ПОТОКАМ ДЛЯ DRT (1) РАСПРОСТРАНИТЬ ИДЕНТИФИКАТОР УКАЗАННЫХ
В СПИСКЕ АДРЕСОВ ПАМЯТИ НА ВСЕ ДРУГИЕ МАШИНЫ И (2) ИЗВЕСТИТЬ ВСЕ ДРУГИЕ МАШИНЫ О ЛЮБОМ ИЗМЕНЕНИИ ЗНАЧЕНИЯ ЛЮБОГО АДРЕСА ПАМЯТИ ИЗ СПИСКА
ПРОДОЛЖЕНИЕ ПРО! {РДУРЫ ЗАГРУЗКИ
103
ФИ Г. 10
СЕТЬ )
МНОГОПОТОЧНАЯ ОБРАБОТКА
РАСПРОСТРАНЕНИЕ (1) ИДЕНТИФИКАТОРА АДРЕСОВ ПАМЯТИ ИЗ СПИСКА НА ВСЕ ДРУГИЕ МАШИНЫ И (2) ИЗВЕЩЕНИЕ ВСЕХ ДРУГИХ МАШИН ОБ ИЗМЕНЕНИИ ЗНАЧЕНИЯ АДРЕСА ПАМЯТИ ИЗ СПИСКА
НОРМАЛЬНОЕ ВЫПОЛНЕНИЕ ПРИЛОЖЕНИЯ
ОБЫЧНАЯ ЗАПИСЬ ПО АДРЕСУ ПАМЯТИ ИЗ СПИСКА
ВОЗОБНОВЛЕНИЕ НОРМАЛЬНОГО ВЫПОЛНЕНИЯ ПРИЛОЖЕНИЯ
111/1
111/2
112
113
114
115
110
111/3
111/4
ФИ Г. 11
МНОГОПОТОЧНАЯ ОБРАБОТКА
НОРМАЛЬНОЕ ВЫПОЛНЕНИЕ ПРИЛОЖЕНИЯ
ОБЫЧНАЯ ЗАПИСЬ ПО АДРЕСУ ПАМЯТИ ИЗ СПИСКА
111/2--- }
112
113
125
ПРЕДПИСАНИЕ ПОТОКАМ СРЕДСТВА DRT РАСПРОСТРАНЯТЬ (1) ИДЕНТИФИКАТОР АДРЕСОВ ПАМЯТИ ИЗ СПИСКА НА ВСЕ ДРУГИЕ МАШИНЫ И (2) ИЗВЕЩАТЬ ВСЕ ДРУГИЕ МАШИНЫ ОБ ИЗМЕНЕНИИ ЗНАЧЕНИЯ АДРЕСА ПАМЯТИ ИЗ СПИСКА
111/1
115
ВОЗОБНОВЛЕНИЕ НОРМАЛЬНОГО ВЫПОЛНЕНИЯ ПРИЛОЖЕНИЯ
DR Т-ОБРА БО ТКА
110
120
128
РАСПРОСТРАНЕНИЕ (1) ИДЕНТИФИКАТОРА АДРЕСОВ ПАМЯТИ ИЗ СПИСКА НА ВСЕ
ДРУГИЕ МАШИНЫ И (2) ИЗВЕЩЕНИЕ ВСЕХ ДРУГИХ
МАШИН ОБ ИЗМЕНЕНИИ ЗНАЧЕНИЯ АДРЕСА ПАМЯТИ ИЗ СПИСКА
127
111/3
121/1
ФИ Г. 12
DRTM1
71/1
128
121/1
ФИГ. 13
__г71/п
DRT Мп
135
ПОЛУЧЕНИЕ ПО СЕТИ ИЗМЕНЕННЫХ ПЕРЕДАННЫХ
ИДЕНТИФИКАТОРА И ЗНАЧЕНИЯ АДРЕСА ПАМЯТИ ИЗ СПИСКА
136
ЗАПИСЬ ПЕРЕДАННОГО ИЗМЕНЕННОГО ЗНАЧЕНИЯ ИДЕНТИФИЦИРОВАННОГО АДРЕСА ПАМЯТИ В ЛОКАЛЬНУЮ ПАМЯТЬ
121/п
9/24
501
50 У
50 <
\ \
ОБЪЕКТ № 3 \
РАСПРЕДЕЛЕННОЕ ИСПОЛНЕНИЕ ПРОГРАММЫ
ОБЪЕКТ № 2
ОБЪЕКТ № 1
! КЛАСС №1
^ВИРТУАЛЬНАЯ ЗА У А -МАШИНА |
50Х
50А
ФИ Г. 14
УРОВЕНЬ ТЕХНИКИ
10/24
Х+1
ФИГ. 15
ВЫЯВЛЕНИЕ ВСЕХ ПОДПРОГРАММ ИНИЦИАЛИЗАЦИИ (Т.Е. И НА ЯЗЫКЕ JAVA)
ВСТАВКА ПОДПРОГРАММЫ , "ВКЛЮЧЕНИЕ/ИСКЛЮЧЕНИЕ" ДЛЯ МОДИФИКАЦИИ КАЖДОЙ ВЫЯВЛЕННОЙ ПОДПРОГРАММЫ
ИНИЦИАЛИЗАЦИИ
ФИ Г. 16
11/24
_^-1
НАЧАЛО ПОДПРОГРАММЫ "ВКЛЮЧЕНИЕ/ИСКЛЮЧЕНИЕ"
ЗАДАНИЕ ГЛОБАЛЬНОГО "ИМЕНИ" ДЛЯ СТРУКТУР, КОНФИГУРАЦИЙ ИЛИ РЕСУРСОВ, ПОДЛЕЖАЩИХ ИНИЦИАЛИЗАЦИИ
ОПРЕДЕЛЕНИЕ СТАТУСА ИНИЦИАЛИЗАЦИИ СТРУКТУР, КОНФИГУРАЦИЙ ИЛИ РЕСУРСОВ, ПОДЛЕЖАЩИХ ИНИЦИАЛИЗАЦИИ
174
¦175
ГЛОБАЛЬНОЕ "ИМЯ" УЖЕ
ИНИЦИАЛИЗИРОВАНО ГДЕ-ЛИБО?
ПРЕРЫВАНИЕ ПОДПРОГРАММЫ ИНИЦИАЛИЗАЦИИ
НЕТ
ПРОДОЛЖЕНИЕ ПОДПРОГРАММЫ ИНИЦИАЛИЗАЦИИ
176
ФИГ. 17
12/24
НАПРАВЛЕНИЕ МАШИНЕ X ЗАПРОСА О СТАТУСЕ ИНИЦИАЛИЗАЦИИ СТРУКТУР, КОНФИГУРАЦИЙ ИЛИ РЕСУРСОВ, ПОДЛЕЖАЩИХ ИНИЦИАЛИЗАЦИИ
ОЖИДАНИЕ ОТ ОПРАШИВАЕМОЙ МАШИНЫ X ОТВЕТА 0 СТАТУСЕ ИНИЦИАЛИЗАЦИИ
^—182
ФИ Г. 18
13/24
ПОЛУЧЕНИЕ ЗАПРОСА О СТАТУСЕ ИНИЦИАЛИЗАЦИИ
191
ОБРАЩЕНИЕ К ОБЩЕЙ ТАБЛИЦЕ ДЛЯ УЗНАВАНИЯ СТАТУСА ИНИЦИАЛИЗАЦИИ, ЧТОБЫ ОПРЕДЕЛИТЬ ИНИЦИАЛИЗИРОВАНА ЛИ УЖЕ СТРУКТУРА, КОНФИГУРАЦИЯ ИЛИ РЕСУРС С ГЛОБАЛЬНЫМ "ИМЕНЕМ"
ОБНОВЛЕНИЕ ЗАПИСИ ГЛОБАЛЬНОГО "ИМЕНИ" В ОБЩЕЙ ТАБЛИЦЕ, КАК ИНИЦИАЛИЗИРОВАННОГО В ДАННЫЙ МОМЕНТ
НАПРАВЛЕНИЕ ОТВЕТА НА ЗАПРОС И СООБЩЕНИЕ, ЧТО ГЛОБАЛЬНОЕ "ИМЯ" РАНЕЕ НЕ ИНИЦИАЛИЗИРОВАНО
192
НАПРАВЛЕНИЕ ОТВЕТА НА ЗАПРОС И
СООБЩЕНИЕ, ЧТО ГЛОБАЛЬНОЕ "ИМЯ"
ПРЕДВАРИТЕЛЬНО ИНИЦИАЛИЗИРОВАНО
194
195
ФИГ. 19
14/24
201
ЗАПУСК ПРОЦЕДУРЫ ЗАГРУЗКИ ПРОГРАММЫ ПРИЛОЖЕНИЯ
ОБНАРУЖЕНИЕ ВСЕХ
202
203
МОДИФИКАЦИЯ КАЖДОЙ ПОДПРОГРАММЫ
204
ПРОДОЛЖЕНИЕ ПРОЦЕДУРЫ ЗАГРУЗКИ ПРОГРАММЫ ПРИЛОЖЕНИЯ
ФИГ. 20
-201
ЗАПУСК ПРОЦЕДУРЫ ЗАГРУЗКИ ПРОГРАММЫ ПРИЛОЖЕНИЯ
s-212
ОБНАРУЖЕНИЕ ВСЕХ ПОДПРОГРАММ
213
МОДИФИКАЦИЯ КАЖДОЙ
ПОДПРОГРАММЫ
г^204
ПРОДОЛЖЕНИЕ ПРОЦЕДУРЫ ЗАГРУЗКИ ПРОГРАММЫ ПРИЛОЖЕНИЯ
ФИГ.21
15/24
161А
I ЗАПУСК ПР01 (ГДУРЫ ЗАГРУЗКИ ~
162 А
ВЫЯВЛЕНИЕ ВСЕХ ПОДПРОГРАММ ОЧИСТКИ -(Т.Е. FINALIZEQ НА ЯЗЫКЕ JAVA )
163В
ВСТАВКА ПОДПРОГРАММЫ "ВКЛЮЧЕНИЕ/ИСКЛЮЧЕНИЕ" / ДЛЯ МОДИФИКАЦИИ КАЖДОЙ ОБНАРУЖЕННОЙ ПОДПРОГРАММЫ ОЧИСТКИ
^.164А
ПРОДОЛЖЕНИЕ ПРОЦЕДУРЫ ЗАГРУЗКИ-
ФИ Г. 22
16/24
_^-171
НАЧАЛО ПОДПРОГРАММЫ "ВКЛЮЧЕНИЕ/ИСКЛЮЧЕНИЕ"
172А
ПОИСК ГЛОБАЛЬНОГО "ИМЕНИ" ДЛЯ СТРУКТУРЫ, КОНФИГУРАЦИИ ИЛИ РЕСУРСА, ПРЕДНАЗНАЧЕННЫХ ДЛЯ
ОЧИСТКИ
ОПРЕДЕЛЕНИЕ СТАТУСА СТРУКТУРЫ, КОНФИГУРАЦИИ ИЛИ РЕСУРСА, ПРЕДНАЗНАЧЕННЫХ ДЛЯ ОЧИСТКИ
_1_
17 4 А
173 А
НЕТ
ПРОДОЛЖЕНИЕ ПОДПРОГРАММЫ ОЧИСТКИ
¦175А
ПРЕРЫВАНИЕ
ПОДПРОГРАММЫ
ОЧИСТКИ
176А
ФИГ.23
17/24
НАПРАВЛЕНИЕ МАШИНЕ X ЗАПРОСА О СТАТУСЕ ОЧИСТКИ СТРУКТУРЫ, КОНФИГУРАЦИИ ИЛИ РЕСУРСА, ПРЕДНАЗНА ЧЕННЫХ ДЛЯ О ЧИСТКИ
-Г"
ОЖИДАНИЕ ОТВЕТА ОТ МАШИНЫ X, ПОЛУЧИВШЕЙ ЗАПРОС 0 СТАТУСЕ ОЧИСТКИ
ФИГ.24
18/24
ПОЛУЧЕНИЕ ЗАПРОСА О СТАТУСЕ ОЧИСТКИ
191А
ОБРАЩЕНИЕ К СЧЕТЧИКУ ОЧИСТКИ ДЛЯ ОПРЕДЕЛЕНИЯ, ПОМЕЧЕНЫ ЛИ СТРУКТУРА, КОНФИГУРАЦИЯ ИЛИ РЕСУРС, ИМЕЮЩИЕ ЗАПРОШЕННОЕ ГЛОБАЛЬНОЕ "ИМЯ", ДЛЯ УДАЛЕНИЯ НА (N-1) МАШИНАХ
192А
НАПРАВЛЕНИЕ ОТВЕТА НА ЗАПРОС, ЧТОБЫ
СООБЩИТЬ, ЧТО ГЛОБАЛЬНОЕ "ИМЯ" НЕ ПОМЕЧЕНО ДЛЯ УДАЛЕНИЯ НА (N-1) МАШИНАХ
НАПРАВЛЕНИЕ ОТВЕТА НА ЗАПРОС, ЧТОБЫ СООБЩИТЬ,
ЧТО ГЛОБАЛЬНОЕ "ИМЯ" ПОМЕЧЕНО ДЛЯ УДАЛЕНИЯ НА (N-1) МАШИНАХ
СЧЕТЧИК "ПОМЕЧЕН
ДЛЯ УДАЛЕНИЯ" УВЕЛИЧИВАЕТСЯ НА ЕДИНИЦУ
ОБНОВЛЕНИЕ В ОБЩЕЙ ТАБЛИЦЕ ЗАПИСИ
ГЛОБАЛЬНОГО "ИМЕНИ" С ПРИДАНИЕМ ЕМУ СТАТУСА "ОЧИЩЕН"
196А
¦197А
ФИГ. 25
19/24
ЗАПУСК ПРОЦЕДУРЫ ЗАГРУЗКИ
1628
ВЫЯВЛЕНИЕ ВСЕХ ПОДПРОГРАММ СИНХРОНИЗАЦИИ-
ВСТАВКА МОДИФИЦИРОВАННОЙ ПОДПРОГРАММЫ СИНХРОНИЗАЦИИ, СОДЕРЖАЩЕЙ ОПЕРАЦИЮ "УСТАНОВИТЬ БЛОКИРАТОР" ПОСЛЕ "MONITOR ENTER" И ОПЕРАЦИЮ "СНЯТЬ БЛОКИРАТОР" ПЕРЕД
"MONITOR EXIT"
10 JO
1648
ФИГ.26
20/24
171В
ВВОД ОПЕРАЦИИ "ПОЛУЧИТЬ БЛОКИРАТОР'
172В
ПОИСК ГЛОБАЛЬНОГО "ИМЕНИ" ОБЪЕКТА, КОНФИГУРАЦИИ ИЛИ РЕСУРСА, ПОДЛЕЖАЩИХ БЛОКИРОВАНИЮ
173В
НАПРАВЛЕНИЕ НА СЕРВЕР БЛОКИРОВАНИЯ (НАПРИМЕР, НА МАШИНУ X) ЗАПРОСА "ПОЛУЧИТЬ БЛОКИРАТОР" ДЛЯ НАЗВАННЫХ ОБЪЕКТА, КОНФИГУРАЦИИ ИЛИ РЕСУРСА
174В
ОЖИДАНИЕ ОТ СЕРВЕРА БЛОКИРОВАНИЯ ОТВЕТА, ПОДТВЕРЖДАЮЩЕГО ПОЛУЧЕНИЕ БЛОКИРАТОРА
ВОЗОБНОВЛЕНИЕ НОРМАЛЬНОГО ВЫПОЛНЕНИЯ ПРОГРАММЫ ПО ПОДТВЕРЖДЕНИИ "ПОЛУЧЕНИЯ БЛОКИРАТОРА"
ФИГ.27
175В
21/24
181В
182 В
{ПОИСК ГЛОБАЛЬНОГО ИМЕНИ ОБЪЕКТА, КОНФИГУРАЦИИ. \ ИЛИ РЕСУРСА, ПОДЛЕЖАЩИХ СНЯТИЮ
183 В
НАПРАВЛЕНИЕ НА СЕРВЕР БЛОКИРОВАНИЯ (НАПРИМЕР, НА МАШИНУ X) ЗАПРОСА "СНЯТЬ БЛОКИРАТОР" ДЛЯ НАЗВАННЫХ ОБЪЕКТА, КОНФИГУРАЦИИ ИЛИ
РЕСУРСА
ОЖИДАНИЕ ОТ СЕРВЕРА БЛОКИРОВАНИЯ ОТВЕТА, ПОДТВЕРЖДАЮЩЕГО "СНЯТИЕ БЛОКИРАТОРА"
184В
I___________,___________
ВОЗОБНОВЛЕНИЕ НОРМАЛЬНОГО ВЫПОЛНЕНИЯ ПРОГРАММЫ ПО ПОДТВЕРЖДЕНИИ "СНЯТИЯ БЛОКИРАТОРА"
ФИГ.28
185В
22/24
ПОЛУЧЕНИЕ ЗАПРОСА "ПОЛУЧИТЬ БЛОКИРАТОР" ДЛЯ НАЗВАННЫХ ОБЪЕКТА, КОНФИГУРАЦИИ ИЛИ
РЕСУРСА
191В
192В
ОБРАЩЕНИЕ К ОБЩЕЙ ТАБЛИЦЕ ИМЕЮЩИХСЯ БЛОКИРАТОРОВ ДЛЯ ОПРЕДЕЛЕНИЯ ТЕКУЩЕГО ВЛАДЕЛЬЦА
--------1________
ЗАДЕРЖКА И ПОСЛЕДУЮЩАЯ ПЕРЕПРОВЕРКА ВЛАДЕЛЬЦА
195В
НЕТ/ \НЕТ
СВОБОДНЫЙ ?
ДОБАВЛЕНИЕ ДАННОГО ЗАПРОСА К ОЧЕРЕДИ ЖДУЩИХ ЗАПРОСОВ НА ПОЛУЧЕНИЕ
194В
ПОМЕТКА БЛОКИРАТОРА КАК НЕСВОБОДНОГО В ОБЩЕЙ ТАБЛИЦЕ
196В
НАПРАВЛЕНИЕ ПОДТВЕРЖДЕНИЯ О ВЛАДЕЛЬЦЕ НА ЗАПРАШИВАЮЩУЮ МАШИНУ
ФИ Г. 29
197В
23/24
202
ПРОВЕРКА ПО ОБЩЕЙ ТАБЛИЦЕ, ЧТО МАШИНА, ЗАПРОСИВШАЯ СНЯТИЕ, НА САМОМ ДЕЛЕ ЯВЛЯЕТСЯ МАШИНОЙ, ВЛАДЕЮЩЕЙ БЛОКИРАТОРОМ В ДАННЫЙ
МОМЕНТ
203
207
ПОМЕТКА ЭТОГО БЛОКИРАТОРА КАК "СВОБОДНОГО" В ОБЩЕЙ ТАБЛИЦЕ
208.
НАПРАВЛЕНИЕ ЗАПРАШИВАЮЩЕЙ
МАШИНЕ ПОДТВЕРЖДЕНИЯ О СНЯТИИ БЛОКИРАТОРА
204
ПОМЕТКА БЛОКИРАТОРА В У ОБЩЕЙ ТАБЛИЦЕ КАК ПОЛУЧЕННОГО СЛЕДУЮЩЕЙ МАШИНОЙ В ОЧЕРЕДИ
I I
20:
НАПРАВЛЕНИЕ ПОДТВЕРЖДЕНИЯ О ПОЛУЧЕНИИ БЛОКИРАТОРА ЗАПРАШИВАЮЩЕЙ МАШИНЕ
206
УДАЛЕНИЕ ЗАПРАШИВАЮЩЕЙ МАШИНЫ ИЗ ОЧЕРЕДИ
ФИГ.ЗО
24/24
ФИГ.ЗЗ