Comments 29
Это все хорошо, но менять внешние/common переменные внутри функции, это прям какой-то 19 век) Не кошерно ни разу, тем более, что все прекрасно решается через параметры или возвращаемое значение.
Не совсем понятно о каких внешних переменных речь?
Скорее всего претензии к некошерности mattod, где массив передаётся по неявной неконстантной ссылке, вместо того что бы вернуть его по значению.
По видимому, "кошерно" выделить память внутри ф-ии и вернуть её по значению, ведь это будет "гораздо эффективнее" и "проще для студентов(-индусов) в поддержке".
На самом деле, все MI работают с _SPCPTR - space pointer - указатель на область данных. mattod и проч - это не функции, а обертки над MI - достаточно низкоуровневая штука. Это вместо ассемблера (который на уровне обычного разработчика недоступен - так сделано для абстракции от конкретного железа).
Есть еще _SYSPTR - это указатель на системный объект. Любая MI, работающая с системными объектами (той же очередью *USRQ) на вход получает этот самый системный указатель. Который нужно сначала получить (один раз) по имени и типу объекта. Примерно так:
#pragma exception_handler(UsrQExeptHandler, 0, _C1_ALL, _C2_ALL, _CTLA_HANDLE_NO_MSG)
pSP = rslvsp(_Usrq, UsrQName, UsrQLib, _AUTH_ALL);
#pragma disable_handler
_Usrq - тип объекта (системная константа), дальше имя и расположение ("библиотека" - это то, что тут вместо папок) ну и права авторизации к объекту.
А вот дальше уже везде будет этот самый системный указатель работать
#pragma exception_handler(UsrQExeptHandler, 0, _C1_ALL, _C2_ALL, _CTLA_HANDLE_NO_MSG)
matqat(&mat_template, spQueue);
#pragma disable_handler
Получение свойств очереди ("материализация очереди"), mat_template - структура куда все это будет укладываться, spQueue - тот самый системный указатель.
Ну и так далее...
Ой, это я съел чего-то! Сейчас посмотрел - все норм (или уже поменяли?). Но тогда лучше всё оформить в отдельную функцию, я про последний кусок кода.
Тоже имел дело с AS-400.... и тоже убедился что там все через ж не как у людей.
Причем в прикладном ПО тред продолжается (DB2 и т.п.)
Согласен с @dyadyaSerezha — если вы меняете внешние переменные внутри функции, это может создать проблемы с предсказуемостью и поддерживаемостью кода. Лучше передавать все через параметры или возвращаемые значения. @SpiderEkb, внешние переменные — это переменные, объявленные за пределами функции, но используемые внутри неё. @Sly_tom_cat, с AS-400 встречался мало, но судя по вашим словам, лучше обойти эту систему стороной, если есть выбор.
но судя по вашим словам, лучше обойти эту систему стороной, если есть выбор
На самом деле нет. Там многое непривычно, но это достаточно мощная и очень богатая возможностями система. И если сейчас уйти куда-то в "обычный мир", то... нет, слишком много чего будет нехватать.
Что касается данного случая - чем это хуже той же memcpy, к примеру? С предсказуемостью и поддерживаемостью там никаких проблем нет - вы передаете указатель на область памяти, которая там внутри заполняется нужным значением. Если не то передадите - получите системное исключение.
Та же matmdata на самом деле обертка над https://www.ibm.com/docs/en/i/7.4?topic=instructions-materialize-machine-data-matmdata
Вспоминается TurboPascal и Delphi (а заодно и Win32 API), где изменение внешних переменных из функции было штатной фичей.
Ну вообще в "чистом" С это тоже нормальная практика.
Но MI, повторюсь, ближе к ассемблеру. Там если указатель, то или _SYSPTR или _SPCPTR
На АС-ке все компиляторы сначала транслируют код в набор MI а потом уже в исполняемый. Более того, MI код также хранится в бинарнике и при переносе на другую платформу система это видит и при первом запуске автоматом перегенерирует исполняемый код.
Это как если у вас программа под x86, а вы ее переносите на ARM. А система при первом запуске вжух! и перегенерировала бинарь. И вы имеете ту же программу, но оптимизированную под тот проч, на котором ее запустили
Ну вообще в "чистом" С это тоже нормальная практика.
В чистом С вроде же всё-таки передаётся указатель в явном виде?
А в паскалях тех оно слегка под капот зарыто, в виде var и out параметров. Т.е. null pointer или указатель на освобождённую память таки можно извернуться и передать, но именно что слегка изворачиваться придется.
Ну тут тоже указатель же. _MI_Time определен как char[8] - имя есть указатель на начало массива.
А в matmdata вообще _SPCPTR т.к. там если не время заказываешь, там другие структуры сосем. В зависимости от значения параметра option.
Ну в RPG (это для работы с БД и бизнес-логики язык, на нем в основном на АСке пишут - более 80% кода) это тоже зарыто.
По умолчанию параметр в процедуру передается по ссылке. Если в прототипе это параметр не указан как value. Тогда по значению. Можно еще указать const - тогда тоже по ссылке, но ссылка будет не на саму переменную, а на ее временную копию (ну и компилятор ругнется если попробуешь его изменить внутри).
null pointer можно передать или если тип переменной явно указан как pointer value, или указав в прототипе для этого аргумента options(*omit) и передавая вместо переменной спецзначение *omit - это и есть передача null вместо указателя на переменную.
Это тонкости в которые вникаешь когда используешь возможности ILE и вызываешь что-то, написанное на С с чем-то, написанном на RPG (т.е. сама программа на RPG, но кусок ее написан на С (потому что так удобнее) - один исходник на RPG, второй на С. Все это компилится в "модули" (аналог объектного файла) соответствующими компилерами и потом линкуется (bind здесь) в один программный объект. Тут надо понимать как правильно прототипы прописать (как типы переменных стыкуются между собой).
На АС-ке все компиляторы сначала транслируют код в набор MI а потом уже в исполняемый.
Т.е. байткод, то, что потом было передрано жабой, С# и прочими?
Не совсем. Там нормальный исполняемый код + TIMI ( Technology Independent Machine Instructions) который нужен для перегенерации исполняемого кода при первом запуске на ином, от того под который изначально было сгенерировано, процессоре.
У нас когда-то сервера были на Power7, потом перешли на Power8. Сейчас Power9. И всегда все программы система при первом после переноса запуске перегенерирует автоматически чтобы исполняемый код был оптимален под тот проц, на котором оно работает.
Дык это от ассемблеров и машинных кодов тянется, там выбора нет — есть регистр длиной сколько-то бит, и либо весь возврат из функции в них укладывается, либо надо пользовать память. А раз память — то ссылка на адрес, по которому функция будет менять байты.
На AS-ке есть т.н. SLIC - System Licensed Internal Code. Это то, что написано под конкретное железо. Но обычному пользователю (разработчику) туда нет доступа. Для разработчика доступно все, что выше него. Доступ к SLIC обеспечивается вот этими самыми MI. Т.е. какое бы та ни было железо, SLIC будет разный, а MI одинаковые.
А поверх MI уже системные API идут. Т.е. MI тут выполняет роль ассемблера (который сам по себе доступен только в SLIC, но не выше).
Они, конечно, уже не с регистрами работают, но достаточно примитивны - указатель на объект, указатель на область памяти, литерал...
Вот пример вызова одной программы из другой с выводом результата на экрвн
DCL SPCPTR .ARG1 INIT(ARG1);
DCL DD ARG1 CHAR(10);
DCL SPCPTR .ARG2 INIT(ARG2);
DCL DD ARG2 CHAR(10);
DCL OL MICPGM2 (.ARG1, .ARG2) ARG;
DCL SYSPTR .MICPGM2;
DCL DD RESOLVE CHAR(34);
DCL DD RESOLVE-TYPE CHAR( 2) DEF(RESOLVE) POS( 1);
DCL DD RESOLVE-NAME CHAR(30) DEF(RESOLVE) POS( 3);
DCL DD RESOLVE-AUTH CHAR( 2) DEF(RESOLVE) POS(33);
ENTRY * EXT;
RESOLVE-TO-PGM:
CPYBLA RESOLVE-TYPE, X'0201';
CPYBLAP RESOLVE-NAME, "MICPGM2" , " ";
RSLVSP .MICPGM2, RESOLVE, *, *;
LOAD-ARGUMENTS-AND-CALL:
CPYBLAP ARG1, "ARG1", " ";
CPYBLAP ARG2, "ARG2", " ";
CALLX .MICPGM2, MICPGM2, *;
BACK-FROM-CALL:
CAT MSG-TEXT, ARG1, ARG2;
CALLI SHOW-MESSAGE, *, .SHOW-MESSAGE;
RETURN:
RTX *;
%INCLUDE SHOWMSG
Это еще в старых версиях - там можно было писать чисто на MI (был компилятор). Сейчас убрали, только использовать С-шные "обертки" можно.
Там еще есть пять уровней защиты системы. От 10-го уровня (отсутствие защиты), до 50-го - защита по сертификату С2 правительства США. Так вот, на уровнях 40 и 50 не все MI доступны пользователью. Есть ограничения. Например, на этих уровнях работа с объектами в домене *SYSTEM через MI запрещена. Только через системные API (более высокий уровень абстракции и интеграции). А через MI можно работать только с объектами в домене *USER.
Я когда с очередями (Data Queue и User Queue) разбирался (думаю, про это отдельно можно будет написать), то столкнулся с этим. Для работы с *DTAQ есть системные API, для *USRQ - нет (только создание и удаление). Но с *DATQ можно работать точно также через MI - те же enq, deq, matqat... Весь код на 99.999% тот же - вся разница в том, что при получении системного указателя на объект (rslvsp) тип объекта не _Usrq, а _Dtaq
Но проблема в том, что *DTAQ может быть создан только в домене *SYSTEM (*USRQ - по выбору, можно в *SYSTEM, можно в *USER). И тут наступает облом - мы работаем на 40-м уровне защиты
При уровне 40 пользователь AS/400 также должен быть зарегистрирован, должен знать правильный пароль для входа в систему и иметь права на доступ к системным ресурсам. Впрочем, пользователи с ограниченными возможностями при этом уровне защиты тоже поддерживаются.
В отличие от уровней 10 — 30, при уровне защиты 40 доступ к нестандартным интерфейсам блокирован. Пользователю теперь доступны далеко не все команды MI, а лишь их разрешенный набор, включая сотни API, разработанных для ISV. Остальные же команды блокированы, то есть система не будет исполнять их в пользовательской программе.
Тем не менее, команды из блокированного набора по-прежнему доступны OS/400. Для различия программ OS/400 и пользовательских, были введены понятия системного и пользовательского состояния, к которым можно отнести любой процесс на AS/ 400. Использование заблокированных команд и доступ, таким образом, к некоторым объектам системы разрешены только в системном состоянии.
цитата из Ф.Солтис "Основы AS/400"
В результате системный указатель-то на объект *DTAQ мне дали, но вот что-то с ним сделать уже нет - любая попытка обратится к объекту по этому указателю приводит к системному исключению ACHTUNG! VERBOTEN!
Получается, что-то типа Java-машины, только реализованной в железе?
В том и дело, что нет. Там есть нормальный исполняемый код (не байт-код). Который генерируется системой из TIMI кода. Но поскольку исполняемый код завязан на конкретное железо, то, чтобы не перекомпилировать руками программу для переноса ее на другую машину (на другом железе, но той же ОС), в программе хранится и TIMI код, позволяющей системе сделать это за вас автоматически (там всегда есть метка под какое железо и версию ОС был сгенерирован исполняемый код).
Т.е. здесь не требуется постоянного присутсвия JVM (или ее аналога) просто чтобы программа работала. Только проверка при запуске - а оно вообще под этот проц скомпилировано?
Вообще, все это достаточно объемно и сложно не только для комментария, но и даже для статьи. Тем более, что все это описано (и переведено) у Солтиса (один из отцов-основателей этой системы) в книге "Основы AS/400"
Из авторского предисловия:
Менее года назад я был в Буэнос-Айресе на встрече с группой пользователей этой системы. По окончании встречи молодой репортер газеты «La Nacion» спросил меня: «Сформулируйте, пожалуйста, коротко причины того, почему в AS/400 столь много новшеств?». И я ответил: «Потому что никто из ее создателей не заканчивал MIT.»
Заинтригованный моим ответом, репортер попросил разъяснений. Я сказал, что не собирался критиковать MIT, а лишь имел в виду то, что разработчики AS/400 имели совершенно иной опыт, нежели выпускники MIT. Так как всегда было трудно заставить кого-либо переехать с восточного побережья в 70-тысячный миннесотский городок, в лаборатории IBM в Рочестере практически не оказалось выпускников университетов, расположенных на востоке США. И создатели AS/400 — представители «школ» Среднего Запада — не были так сильно привязаны к проектным решениям, используемым другими компаниями.
И еще из предисловия
IBM AS/400 — одна из самых интересных по инженерным решениям и эффективных коммерчески компьютерных архитектур. Задолго до того, как термин «объектно-ориентированный» широко распространился, машинный интерфейс высокого уровня AS/400, появившийся в предшествовавшей ей System/38, предоставил разработчикам приложений набор объектов (таких как очереди, индексы и файлы базы данных), которые при создании программы можно было использовать в качестве строительных блоков. Объекты придали высоким функциональным возможностям системы согласованную и простую в работе форму. Унифицированный объектный интерфейс скрывает от программистов AS/400 детали, благодаря чему они могут игнорировать сложные управляющие блоки и системные процедуры, относящиеся к внутренним процессам операционной системы (ОС). Более того, с помощью набора заранее определенных операций ОС ограничивает доступ к объектам. Это обеспечивает приложениям дополнительную защиту при исполнении.
Это система, целиком и полностью построенная на единой концепции "все есть объект". Тут даже нет файлов и папок - есть объекты - имя, тип, атрибуты. И для каждого типа системой определен допустимый набор операций. Если в иных системах вы можете открыть программу в hex редакторе и поправить какие-то байты в исполняемом коде, то тут это физически невозможно - такая операция не определена системой для объекта типа *PGM.
Объект типа *PGM нельзя прочитать системными средствами как набор данных?
А изменить тип можно?
Тут, кстати, появляется ловушка - мы можем создать (системным API) *USRQ в домене *SYSTEM, но на уровне 40+ ничего с ней с делать не сможем т.к. вся работа с ней только через MI, которые в данном случае будут запрещены.
Поэтому в своем USRQ API я жестко зафиксировал создание *USRQ только в *USER.
Ибо значение 0x8000000000000000 тут соответствует началу тысячелетия - 01/01/2000 00:00:00.000000
Но... это же не начало тысячелетия.
Как интересно, я на AS/400 работал, программировал, преподавал и отвечал за продажи в ИБМ. И даже автор редбука по кластерным технологиям. Но чтобы в MI лазить - не, такого не было), не думаю, что это IBM way. Честно говоря, удивлен, что эта платформа еще где-то используется.
Но чтобы в MI лазить - не, такого не было), не думаю, что это IBM way.
Ну так скажем - более 80% кода там пишется на RPG (это тема для отдельной статьи)
Но С/С++ там есть (правда, старенькие - 11-й год).
Некоторые вещи без MI не сделать. Тот же самый USRQ - есть API для создания и удаления. И все. Читать-писать и все остальное - только через MI. А вещь полезная и удобная. Я для наших задач делал USRQ API (можно использовать из С/С++ или RPG, есть CL команды, есть SQL UDF/UDTF - например, посмотреть скулем содержимое очереди
CL
DSPUSRQ USRQ(TSTQUE)
SQL
select *
from table(ALIBVPN.USER_QUEUE_ENTRIES('TSTQUE'));
Ядро всего этого написано на С в модели памяти TERASPACE с 64-бит указателями. Оформлено в виде SVRPGM. Ну а пользоваться уже откуда угодно можно.
Когда-то в системе был MI компилятор - видел MI код от Leif Svalgaard, Junlei Li - ну почти ассемблер...
Потом убрали, оставили только С-врапперы для ряда MI.
Честно говоря, удивлен, что эта платформа еще где-то используется.
У нас - как минимум Альфа, Росбанк, Райф, может еще где есть. Были еще машинки в РЖД и ПФР (как сейчас - не знаю).
В мире - Top Companies Using IBM i
Ну и ресурсов хватает. Система, конечно, нишевая, но вполне себе используется и развивается - раз в 2-3 года новая версия (сейчас 7.5 самая свежая), 2-3 раза в год - свежий TR (Technology Refresh - минорное обновление системы). Ну и железо - мы на Power9 сидим (IBM Power E980, 120 ядер Power9, RAM 12Тб, 400Тб на SSD, IBM i 7.4), сейчас уже Power10 есть.
Так что рано хоронить :-)
Эх, а сделали бы 10 "бит уникальности" вместо 12, хватило бы на 250 лет.
нда, прямо как действительно про другой мир рассказываете, зазеркалье какое-то, технологии Древних из мира Фоллаута. Ооочень интересно. Я из IBM-овских машин лично видел какую-то бандуру из z серии, не ней в качестве ОС был какой-то AIX, и там тоже был терминал с зелеными буквами, но нужна она была только для того, чтоб запустить на ней Oracle DB, а над Ораклом - учетную систему банка. Это был примерно 2005 год.
Понять и проникнуться духом, что это было такое, как оно устроено, и как с этим правильно работать, я тогда не успел - обстоятельства менялись, мне пришлось переезжать в другой город, ну а потом вжух-вжух и вот уже внезапно наступил 2024, и все строят свои инфраструктуры на linux, docker, kuber, kafka, rabbit, postgres, mongo, JVM based solutions и много других новых слов.
IBM-овских машин лично видел какую-то бандуру из z серии, не ней в качестве ОС был какой-то AIX
Это мейнфреймы. IBM z - потомок Sysyem/390. AIX - более традиционная, UNIX-подобная ОС.
IBM i - переименованная AS/400 - потомок System/38. Поменьше машинки. Middleware - сначала позиционировались как серверы для малого и среднего бизнеса. Но получилась настолько мощной и масштабируемой что пошла и крупный бизнес. Но ОС там вообще ни на что не похожа принципиально.
и там тоже был терминал с зелеными буквами
Скорее всего IBM 3270 У нас тоже "с зелеными буквами". В простонародье "гринскрин". Но другой - IBM 5250. Сейчас, конечно, уже не терминал, а софтовый эмулятор. Мы используем Access Client Solutions (бесплатный пакет от IBM - там много чего кроме терминала для работы с сервером).
нужна она была только для того, чтоб запустить на ней Oracle DB, а над Ораклом - учетную систему банка
Аналогично. Только БД тут интегрирована в систему, DB2. И да, тоже крутится АБС банка.
все строят свои инфраструктуры на linux, docker, kuber, kafka, rabbit, postgres, mongo, JVM based solutions и много других новых слов
Это другие решения. Они дешевле (там много бесплатного и опенсорсного). Но это белее универсальное. А тут - платформа специализированная именно под бизнес-логику в первую очередь. Это изначально "многопользовательская" система. Каждый процесс в своем изолированном от остальных задании (job) работает. Т.е. контейнеры как бы и не нужны. БД, компиляторы, все средства администрирования - все интегрировано в систему. Отдельно ставили только очередь (IBM MQ, сейчас вот еще кафку прикрутили), но это для общения с внешним миром (тут еще куча "внешних систем", они на других платформах работают - там и RHEL и SLES есть и еще много чего). Для локальных задач есть системные объекты-очереди, более легкие, простые и быстрые (на эту тему будет отдельная статья). Основной язык - RPG Весьма быстр, удобен и эффективен для работы с БД и бизнес-логики т.к. там никаких внешних зависимостей не нужно. В языке есть все для работы с БД (хоть SQL в код встраивай когда нужно) и работы со строками, датой, временем, фиксированной точкой (практически все типы данных, что есть в БД поддерживаются в языке).
Один минус - это достаточно дорогое решение. Ну и один раз подсев, уже не соскочишь... И разработчиков в стране не так много - Альфа, Райф, Росбанк на этой системе сидят. Ну вендоры есть, кто может под нее что-то делать - BTC, Cinimex, RMS-Lab...
Действительно, такой себе параллельный мир.
Standard Time как его видит IBM