Как разделить память между программой linux и программой Windows, проходящей через Wine (тот же компьютер)?

Есть ли способ (а затем как) обмениваться памятью между программой linux и программой Windows, проходящей через вино?

Так как может быть трудно понять, зачем это делать, я даю вам свою ситуацию: у меня есть проприетарная программа, скомпилированная только для окон, но у этой программы есть открытый API плагина C. Но я хотел бы сделать часть моего кода, запущенного на родном приложении (и использовать другие библиотеки и другие преимущества Linux), и сделать IPC в быстром режиме

Ответ 1

Цель Wine - предоставить среду WinAPI -like для систем Unix (-like). Это означает, что Вино можно рассматривать как отдельную, независимую от API, "независимую" операционную систему сверху и вдоль системы Unix -like. Таким образом, эта машина, на которую вы говорите, может иметь две ОС, одну над другой. Во-первых, "реальный" (управляющий реальным оборудованием), т.е. GNU/Linux. Во-вторых, есть реализация WinAPI, известная как Wine в верхней части интерфейсов POSIX/SUS.

И, что касается человечества, есть один и только один переносимый способ создания межпроцессной связи между машинами с разными операционными системами и, как вы уже заметили, я имею в виду сокеты.

Подсистему Wine можно считать полувиртуальной машиной по своему усмотрению, изолированной от ядра Linux, но тесно связанной с ней в одно и то же время.

Для повышения эффективности мое предложение состоит в том, чтобы использовать то, что сокеты в сочетании с тем, что я называю SHMNP (Сетевой протокол общей памяти) для обеспечения общей общей памяти. Опять же, помните, что обе машины (хотя это физически только одна) должны быть независимыми. Реализация вина слишком грязная, чтобы неуклюжие детали были легко обходимы (хотя это ничто по сравнению с хакерами Cygwin).

SHMNP работает таким образом. Обратите внимание, однако, что SHMNP не существует! Это просто теоретические, и протокольные структуры и др. Не представлены по очевидным причинам.

  • Обе машины создают собственные области сокетов/разделяемой памяти (предполагается, что они ранее согласовали размер области). В то же время они выбирают номер порта, и одна из машин становится сервером, другая - клиентом. Соединение инициализируется.

  • Первоначально вся "общая" память на обеих машинах содержит неинициализированные данные (другая машина может иметь разные значения для любого данного блока разделяемой памяти).

  • Пока соединение не будет закрыто, если какая-либо из двух машин напишет на любой из адресов области разделяемой памяти, сообщение должно быть отправлено на другую машину с измененной информацией. Яркие функции ядра Linux могут быть использованы, чтобы позволить даже грубым указателям работать с этим прекрасно (см. Ниже). Однако я не знаю, как это сделать в Windows, а не с помощью специализированных процедур ReadNetworkShared() и WriteNetworkShared() -like.

  • Реализация может обеспечить какой-то механизм синхронизации, поэтому разрешить сетевые семафоры, мьютексы и т.д.

Специфические особенности ядра Linux: большинство современных аппаратных архитектур и операционных систем общего назначения обеспечивают способ защиты памяти от вредоносного/багги/непреднамеренного использования пользовательским процессом. Всякий раз, когда вы читаете/записываете в память, которая не отображается в виртуальном адресном пространстве процесса, ЦП будет уведомлять ядро операционной системы о том, что произошла ошибка страницы. Впоследствии ядро (если Unix (-like)) отправит сигнал нарушения сегментации в процесс нарушения, или, другими словами, вы получите SIGSEGV.

Скрытый магический секрет заключается в том, что SIGSEGV может быть пойман и обработан. Таким образом, мы можем mmap() некоторую память (область разделяемой памяти), пометить ее как mprotect() только для чтения с помощью mprotect(), тогда всякий раз, когда мы пытаемся записать адрес в области разделяемой памяти, процесс получит SIGSEGV. Обработчик сигнала впоследствии выполняет проверки в siginfo_t переданные ядром, и выводит одно из двух действий.

  • Если неисправный адрес не находится в области общей памяти, abort() или что-то еще.
  • В противном случае записываемая страница должна быть скопирована во временное хранилище (возможно, с помощью splice()?). Затем отметьте, чтобы страница была написана как чтение/запись, и установите таймер так, чтобы в течение таймаута страница снова была помечена как прочитанная, и отправлена (возможно сжатая) разница между старой копией и текущей записью через гнездо (SIMD может помочь вам здесь). Затем обработчик возвращается, позволяя писать (и, возможно, другие записи!), Чтобы завершить без дальнейшего вмешательства, пока не погаснет таймер.

Всякий раз, когда машина получает сжатые данные через сокет, он просто распаковывается и записывается там, где он принадлежит.

Надеюсь, это поможет вам!

Изменить: я только что нашел явный недостаток предварительного редактирования. Если на другой компьютер была отправлена (сжатая) страница, эта другая машина не сможет различать данные, которые были изменены на странице, и данные, которые не были изменены. Это связано с состоянием гонки, когда принимающая машина может потерять информацию, которую она еще не отправила. Однако некоторые другие вещи, специфичные для Linux-ядра, исправляют его.

Ответ 2

Я не уверен, что это хорошая идея, или если она даже будет работать, но вы можете создавать файлы в /dev/shm и обращаться к ним как из Wine, так и из вашего родного Linux-приложения.

Он не гарантированно существует, поэтому у вас должен быть резервный IPC-метод.

https://superuser.com/info/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. Я также не уверен, будет ли это работать.