mirror of
https://github.com/brunodev85/winlator.git
synced 2024-11-26 22:50:32 +00:00
Add android_sysvshm
This commit is contained in:
parent
5805b57f1f
commit
421f5ba652
11
android_sysvshm/CMakeLists.txt
Normal file
11
android_sysvshm/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
project(AndroidSysVSHM C)
|
||||
message("Building ${PROJECT_NAME}")
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE on)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -std=gnu99 -shared -fPIC")
|
||||
|
||||
MESSAGE(STATUS "Compiler options: ${CMAKE_C_FLAGS}")
|
||||
|
||||
add_library(android-sysvshm SHARED android_sysvshm.c)
|
6
android_sysvshm/README.md
Normal file
6
android_sysvshm/README.md
Normal file
@ -0,0 +1,6 @@
|
||||
This is the Android SysVSHM used in Winlator based on https://github.com/pelya/android-shmem
|
||||
|
||||
## Build dependencies
|
||||
|
||||
$ dpkg --add-architecture armhf
|
||||
$ apt install build-essential make cmake g++-arm-linux-gnueabihf
|
255
android_sysvshm/android_sysvshm.c
Normal file
255
android_sysvshm/android_sysvshm.c
Normal file
@ -0,0 +1,255 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "sys/shm.h"
|
||||
|
||||
#define REQUEST_CODE_SHMGET 0
|
||||
#define REQUEST_CODE_GET_FD 1
|
||||
#define REQUEST_CODE_DELETE 2
|
||||
|
||||
#define MIN_REQUEST_LENGTH 5
|
||||
#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
|
||||
|
||||
/* based on https://github.com/pelya/android-shmem */
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
void* addr;
|
||||
int fd;
|
||||
size_t size;
|
||||
char marked_for_delete;
|
||||
} shmemory_t;
|
||||
|
||||
static shmemory_t* shmemories = NULL;
|
||||
static int shmemory_count = 0;
|
||||
static int sysvshm_server_fd = -1;
|
||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static int find_shmemory_index(int shmid) {
|
||||
for (int i = 0; i < shmemory_count; i++) if (shmemories[i].id == shmid) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void sysvshm_connect() {
|
||||
if (sysvshm_server_fd >= 0) return;
|
||||
char* path = getenv("ANDROID_SYSVSHM_SERVER");
|
||||
|
||||
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd < 0) return;
|
||||
|
||||
struct sockaddr_un server_addr;
|
||||
memset(&server_addr, 0, sizeof(server_addr));
|
||||
server_addr.sun_family = AF_LOCAL;
|
||||
|
||||
strncpy(server_addr.sun_path, path, sizeof(server_addr.sun_path) - 1);
|
||||
|
||||
int res;
|
||||
do {
|
||||
res = 0;
|
||||
if (connect(fd, (struct sockaddr*)&server_addr, sizeof(struct sockaddr_un)) < 0) res = -errno;
|
||||
}
|
||||
while (res == -EINTR);
|
||||
|
||||
if (res < 0) {
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
sysvshm_server_fd = fd;
|
||||
}
|
||||
|
||||
static void sysvshm_close() {
|
||||
if (sysvshm_server_fd >= 0) {
|
||||
close(sysvshm_server_fd);
|
||||
sysvshm_server_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int sysvshm_shmget_request(size_t size) {
|
||||
if (sysvshm_server_fd < 0) return 0;
|
||||
|
||||
char request_data[MIN_REQUEST_LENGTH];
|
||||
request_data[0] = REQUEST_CODE_SHMGET;
|
||||
memcpy(request_data + 1, &size, 4);
|
||||
|
||||
int res = write(sysvshm_server_fd, request_data, sizeof(request_data));
|
||||
if (res < 0) return 0;
|
||||
|
||||
int shmid;
|
||||
res = read(sysvshm_server_fd, &shmid, 4);
|
||||
return res == 4 ? shmid : 0;
|
||||
}
|
||||
|
||||
static int sysvshm_get_fd_request(int shmid) {
|
||||
if (sysvshm_server_fd < 0) return 0;
|
||||
|
||||
char request_data[MIN_REQUEST_LENGTH];
|
||||
request_data[0] = REQUEST_CODE_GET_FD;
|
||||
memcpy(request_data + 1, &shmid, 4);
|
||||
|
||||
int res = write(sysvshm_server_fd, request_data, sizeof(request_data));
|
||||
if (res < 0) return -1;
|
||||
|
||||
char zero = 0;
|
||||
struct iovec iovmsg = {.iov_base = &zero, .iov_len = 1};
|
||||
struct {
|
||||
struct cmsghdr align;
|
||||
int fds[1];
|
||||
} ctrlmsg;
|
||||
|
||||
struct msghdr msg = {
|
||||
.msg_name = NULL,
|
||||
.msg_namelen = 0,
|
||||
.msg_iov = &iovmsg,
|
||||
.msg_iovlen = 1,
|
||||
.msg_flags = 0,
|
||||
.msg_control = &ctrlmsg,
|
||||
.msg_controllen = sizeof(struct cmsghdr) + sizeof(int)
|
||||
};
|
||||
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = msg.msg_controllen;
|
||||
((int*)CMSG_DATA(cmsg))[0] = -1;
|
||||
|
||||
recvmsg(sysvshm_server_fd, &msg, 0);
|
||||
return ((int*)CMSG_DATA(cmsg))[0];
|
||||
}
|
||||
|
||||
static void sysvshm_delete_request(int shmid) {
|
||||
if (sysvshm_server_fd < 0) return;
|
||||
|
||||
char request_data[MIN_REQUEST_LENGTH];
|
||||
request_data[0] = REQUEST_CODE_DELETE;
|
||||
memcpy(request_data + 1, &shmid, 4);
|
||||
|
||||
write(sysvshm_server_fd, request_data, sizeof(request_data));
|
||||
}
|
||||
|
||||
static void sysvshm_delete(int index) {
|
||||
sysvshm_connect();
|
||||
sysvshm_delete_request(shmemories[index].id);
|
||||
sysvshm_close();
|
||||
|
||||
if (shmemories[index].fd >= 0) close(shmemories[index].fd);
|
||||
shmemory_count--;
|
||||
memmove(&shmemories[index], &shmemories[index+1], (shmemory_count - index) * sizeof(shmemory_t));
|
||||
}
|
||||
|
||||
int shmget(key_t key, size_t size, int flags) {
|
||||
if (key != IPC_PRIVATE) return -1;
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
sysvshm_connect();
|
||||
int shmid = sysvshm_shmget_request(size);
|
||||
if (shmid == 0) {
|
||||
sysvshm_close();
|
||||
pthread_mutex_unlock(&mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size = ROUND_UP(size, getpagesize());
|
||||
int index = shmemory_count;
|
||||
shmemory_count++;
|
||||
shmemories = realloc(shmemories, shmemory_count * sizeof(shmemory_t));
|
||||
shmemories[index].size = size;
|
||||
shmemories[index].fd = sysvshm_get_fd_request(shmid);
|
||||
shmemories[index].addr = NULL;
|
||||
shmemories[index].id = shmid;
|
||||
shmemories[index].marked_for_delete = 0;
|
||||
|
||||
sysvshm_close();
|
||||
|
||||
if (shmemories[index].fd < 0) {
|
||||
shmemory_count--;
|
||||
shmemories = realloc(shmemories, shmemory_count * sizeof(shmemory_t));
|
||||
pthread_mutex_unlock(&mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
return shmid;
|
||||
}
|
||||
|
||||
void* shmat(int shmid, const void* shmaddr, int shmflg) {
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
void* addr;
|
||||
int index = find_shmemory_index(shmid);
|
||||
if (index != -1) {
|
||||
if (shmemories[index].addr == NULL) {
|
||||
shmemories[index].addr = mmap(NULL, shmemories[index].size, PROT_READ | (shmflg == 0 ? PROT_WRITE : 0), MAP_SHARED, shmemories[index].fd, 0);
|
||||
if (shmemories[index].addr == MAP_FAILED) shmemories[index].addr = NULL;
|
||||
}
|
||||
addr = shmemories[index].addr;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
return addr ? addr : (void *)-1;
|
||||
}
|
||||
|
||||
int shmdt(const void* shmaddr) {
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
for (int i = 0; i < shmemory_count; i++) {
|
||||
if (shmemories[i].addr == shmaddr) {
|
||||
munmap(shmemories[i].addr, shmemories[i].size);
|
||||
shmemories[i].addr = NULL;
|
||||
if (shmemories[i].marked_for_delete) sysvshm_delete(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int shmctl(int shmid, int cmd, struct shmid_ds* buf) {
|
||||
if (cmd == IPC_RMID) {
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
int index = find_shmemory_index(shmid);
|
||||
if (index != -1) {
|
||||
if (shmemories[index].addr) {
|
||||
shmemories[index].marked_for_delete = 1;
|
||||
}
|
||||
else sysvshm_delete(index);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
return 0;
|
||||
}
|
||||
else if (cmd == IPC_STAT) {
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
int index = find_shmemory_index(shmid);
|
||||
if (!buf || index == -1) {
|
||||
pthread_mutex_unlock(&mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(buf, 0, sizeof(struct shmid_ds));
|
||||
buf->shm_segsz = shmemories[index].size;
|
||||
buf->shm_nattch = 1;
|
||||
buf->shm_perm.__key = IPC_PRIVATE;
|
||||
buf->shm_perm.uid = geteuid();
|
||||
buf->shm_perm.gid = getegid();
|
||||
buf->shm_perm.cuid = geteuid();
|
||||
buf->shm_perm.cgid = getegid();
|
||||
buf->shm_perm.mode = 0666;
|
||||
buf->shm_perm.__seq = 1;
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
15
android_sysvshm/build.sh
Normal file
15
android_sysvshm/build.sh
Normal file
@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
rm -r build64
|
||||
mkdir build64
|
||||
cd build64
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=../cross-arm64.cmake
|
||||
make -j8
|
||||
|
||||
cd ..
|
||||
|
||||
rm -r build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=../cross-armhf.cmake
|
||||
make -j8
|
3
android_sysvshm/cross-arm64.cmake
Normal file
3
android_sysvshm/cross-arm64.cmake
Normal file
@ -0,0 +1,3 @@
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CROSS_PATH "/usr/lib/aarch64-linux-gnu")
|
||||
set(CMAKE_C_COMPILER "aarch64-linux-gnu-gcc")
|
3
android_sysvshm/cross-armhf.cmake
Normal file
3
android_sysvshm/cross-armhf.cmake
Normal file
@ -0,0 +1,3 @@
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CROSS_PATH "/usr/lib/arm-linux-gnueabihf")
|
||||
set(CMAKE_C_COMPILER "arm-linux-gnueabihf-gcc")
|
102
android_sysvshm/sys/shm.h
Normal file
102
android_sysvshm/sys/shm.h
Normal file
@ -0,0 +1,102 @@
|
||||
#ifndef _SYS_SHM_H
|
||||
#define _SYS_SHM_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* The following System V style IPC functions implement a shared memory
|
||||
facility. The definition is found in XPG4.2. */
|
||||
|
||||
/* Mode bits for `msgget', `semget', and `shmget'. */
|
||||
#define IPC_CREAT 01000 /* Create key if key does not exist. */
|
||||
#define IPC_EXCL 02000 /* Fail if key exists. */
|
||||
#define IPC_NOWAIT 04000 /* Return error on wait. */
|
||||
|
||||
/* Control commands for `msgctl', `semctl', and `shmctl'. */
|
||||
#define IPC_RMID 0 /* Remove identifier. */
|
||||
#define IPC_SET 1 /* Set `ipc_perm' options. */
|
||||
#define IPC_STAT 2 /* Get `ipc_perm' options. */
|
||||
#define IPC_INFO 3 /* See ipcs. */
|
||||
|
||||
/* Special key values. */
|
||||
#define IPC_PRIVATE ((key_t) 0) /* Private key. */
|
||||
|
||||
/* Permission flag for shmget. */
|
||||
#define SHM_R 0400 /* or S_IRUGO from <linux/stat.h> */
|
||||
#define SHM_W 0200 /* or S_IWUGO from <linux/stat.h> */
|
||||
|
||||
/* Flags for `shmat'. */
|
||||
#define SHM_RDONLY 010000 /* attach read-only else read-write */
|
||||
#define SHM_RND 020000 /* round attach address to SHMLBA */
|
||||
#define SHM_REMAP 040000 /* take-over region on attach */
|
||||
#define SHM_EXEC 0100000 /* execution access */
|
||||
|
||||
/* Commands for `shmctl'. */
|
||||
#define SHM_LOCK 11 /* lock segment (root only) */
|
||||
#define SHM_UNLOCK 12 /* unlock segment (root only) */
|
||||
|
||||
/* Type to count number of attaches. */
|
||||
typedef unsigned long int shmatt_t;
|
||||
typedef long int __long_time_t; /* to keep compatibility to Debian Wheezy armhf */
|
||||
/*
|
||||
typedef int32_t __key_t;
|
||||
typedef __key_t key_t;
|
||||
typedef uint32_t __uid_t;
|
||||
typedef uint32_t __gid_t;
|
||||
*/
|
||||
|
||||
/* Data structure used to pass permission information to IPC operations. */
|
||||
struct debian_ipc_perm /* We cannot use Android version, because there are no padding fields */
|
||||
{
|
||||
key_t __key; /* Key. */
|
||||
__uid_t uid; /* Owner's user ID. */
|
||||
__gid_t gid; /* Owner's group ID. */
|
||||
__uid_t cuid; /* Creator's user ID. */
|
||||
__gid_t cgid; /* Creator's group ID. */
|
||||
unsigned short int mode; /* Read/write permission. */
|
||||
unsigned short int __pad1;
|
||||
unsigned short int __seq; /* Sequence number. */
|
||||
unsigned short int __pad2;
|
||||
unsigned long int __unused1;
|
||||
unsigned long int __unused2;
|
||||
};
|
||||
|
||||
/* Data structure describing a shared memory segment. */
|
||||
struct shmid_ds
|
||||
{
|
||||
struct debian_ipc_perm shm_perm; /* operation permission struct */
|
||||
size_t shm_segsz; /* size of segment in bytes */
|
||||
__long_time_t shm_atime; /* time of last shmat() */
|
||||
unsigned long int __unused1;
|
||||
__long_time_t shm_dtime; /* time of last shmdt() */
|
||||
unsigned long int __unused2;
|
||||
__long_time_t shm_ctime; /* time of last change by shmctl() */
|
||||
unsigned long int __unused3;
|
||||
__pid_t shm_cpid; /* pid of creator */
|
||||
__pid_t shm_lpid; /* pid of last shmop */
|
||||
shmatt_t shm_nattch; /* number of current attaches */
|
||||
unsigned long int __unused4;
|
||||
unsigned long int __unused5;
|
||||
};
|
||||
|
||||
/* Shared memory control operation. */
|
||||
extern int shmctl (int __shmid, int __cmd, struct shmid_ds *__buf);
|
||||
|
||||
/* Get shared memory segment. */
|
||||
extern int shmget (key_t __key, size_t __size, int __shmflg);
|
||||
|
||||
/* Attach shared memory segment. */
|
||||
extern void *shmat (int __shmid, const void *__shmaddr, int __shmflg);
|
||||
|
||||
/* Detach shared memory segment. */
|
||||
extern int shmdt (const void *__shmaddr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* sys/shm.h */
|
Loading…
Reference in New Issue
Block a user