Есть ли способ (и как потом) делить память между программой linux и программой windows, работающей через wine?
Поскольку может быть трудно понять, почему так поступить, я приведу вам свою ситуацию:
У меня есть проприетарная программа, скомпилированная только для Windows, но у этой программы есть открытый API плагина Си. Но я хотел бы, чтобы часть моего кода работала на нативном приложении (и использовала другие библиотеки и другие преимущества linux) и быстро выполняла IPC
Цель Wine — предоставить WinAPI-подобную среду в Unix-подобных системах. Это подразумевает, что Wine можно рассматривать как отдельную «независимую» операционную систему с API-интерфейсом сверху и вдоль Unix-подобной системы. Таким образом, у той машины, которую вы говорите, на самом деле может быть две ОС, одна над другой. Во-первых, «реальный» (управляющий реальным оборудованием), то есть GNU / Linux. Во-вторых, существует реализация WinAPI, известная как Wine, поверх интерфейсов POSIX / SUS.
И что касается человечества, есть один и только один единственный переносимый способ создания межпроцессного взаимодействия между машинами с разными операционными системами, и, как вы, возможно, уже заметили, я имею в виду сокеты.
Подсистема Wine по праву может считаться полувиртуальной машиной, изолированной от ядра Linux, но в то же время тесно связанной с ней.
В целях эффективности мое предложение состоит в том, чтобы использовать эти сокеты в сочетании с тем, что я называю SHMNP (Сетевой протокол с общей памятью), для обеспечения общей сетевой памяти. Опять же, помните, что обе «машины» (хотя физически это всего лишь одна) должны быть независимыми. Реализация Wine слишком грязная, чтобы неуклюжие детали не могли быть легко обработаны (хотя это ничто по сравнению с взломами Cygwin).
SHMNP работает таким образом. Обратите внимание, однако, что SHMNP делает не существовать! Это просто теоретические и протокольные структуры и другие не представлены по понятным причинам.
Обе машины создают свои собственные области сокетов / разделяемой памяти (предполагается, что они согласовали размер области ранее). В то же время они выбирают номер порта, и одна из машин становится сервером, а другая становится клиентом. Соединение инициализировано.
Первоначально вся «общая» память на обеих машинах содержит неинициализированные данные (другая машина может иметь разные значения для любого данного блока общей памяти).
До тех пор, пока соединение не будет закрыто, если какая-либо из двух машин выполнит запись по какому-либо из адресов области совместно используемой памяти, на другую машину должно быть отправлено сообщение с информацией, которая изменилась. Причудливые возможности ядра Linux могут быть использованы для того, чтобы даже сырые указатели прекрасно с этим работали (см. Ниже). Я, однако, не знаю, делать это в Windows, а специализированными ReadNetworkShared()
а также WriteNetworkShared()
подобные процедуры.
Реализация может обеспечить некоторый механизм синхронизации, чтобы разрешить семафоры в сети, мьютексы, и другие.
Особенности ядра Linux:
Большинство современных аппаратных архитектур и операционных систем общего назначения обеспечивают способ защиты памяти от злонамеренного / ошибочного / непреднамеренного использования пользовательским процессом. Всякий раз, когда вы выполняете чтение / запись в память, которая не отображена в виртуальном адресном пространстве вашего процесса, ЦП уведомит ядро операционной системы о том, что ошибка страницы произошло Впоследствии ядро (если Unix (-подобно)) отправит сигнал нарушения сегментации в вызывающий процесс, или, другими словами, вы получите SIGSEGV.
Тайный магический секрет в том, что SIGSEGV может быть пойман и обработан. Таким образом, мы можем mmap()
некоторая память (область общей памяти), пометьте ее как доступную только для чтения mprotect()
затем, всякий раз, когда мы пытаемся записать адрес в области общей памяти, процесс получит SIGSEGV. Обработчик сигнала впоследствии выполняет проверки в siginfo_t
передается ядром и выводит одно из двух действий.
abort()
или что угодно.splice()
?). Затем пометьте страницу для записи как доступную для чтения / записи и настройте таймер так, чтобы в течение тайм-аута страница снова помечалась только для чтения, и отправлялась разница (возможно, сжатая) между старой копией и теперь записанной страницей. через гнездо (SIMD может помочь вам здесь). Затем обработчик возвращается, позволяя завершить запись (и, возможно, другие записи!) Без дальнейшего вмешательства, пока не сработает таймер.Всякий раз, когда машина получает сжатые данные через сокет, она просто распаковывается и записывается в том месте, где она принадлежит.
Надеюсь, это поможет вам!
редактироватьЯ только что обнаружил очевидный недостаток предварительного редактирования дизайна. Если (сжатая) страница была отправлена на другой компьютер, этот другой компьютер не сможет различить данные, которые были изменены на странице, и данные, которые не были изменены. Это связано с состоянием гонки, когда принимающая машина может потерять информацию, которую она еще не отправила. Тем не менее, некоторые вещи, специфичные для ядра Linux, исправляют это.
Я не уверен, что это хорошая идея или если она вообще будет работать, но вы можете создавать файлы в /dev/shm
и доступ к ним как из Wine, так и из вашего собственного приложения Linux
Это не гарантировано, поэтому у вас должен быть запасной метод IPC.
https://superuser.com/questions/45342/when-should-i-use-dev-shm-and-when-should-i-use-tmp
В противном случае вы можете попробовать создать приложение winelib, которое может вызывать ваш код Windows из Linux: http://web.archive.org/web/20150225173552/http://wine-wiki.org/index.php/WineLib#Calling_a_Native_Windows_dll_from_Linux. Я также не уверен, будет ли это работать.