/********************************************************************** * * * mem.cc * * * * Implement shared memory for GNU APL. Vectors of the same type are * * stored in memory buffers (mmap and munmap interfaces are provided) * * The handle to access the file is provided by Quad FIO (fopen), and * * a pointer to memory is provided. The size in bytes (chars) of each * * supported type is provided, and is used to compute strides. Vector * * of each type can be transferred between the buffer and an APL * * vector. The memory vectors must be of only one type. In future, * * the APL primitives may be enhanced to support these uni-type * * vectors directly, as this maximizes cache/memory performance. * * The current advantage to using mem.cc is that the APL Workspace is * * not bloated with data, and the data is not even read if it is not * * used. * * * * Copyright (C) 2017 Fred Weigel * * * * This program is free software: you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation, either version 3 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see * * . * * * **********************************************************************/ #include #include #include #include #include #include "../Value.icc" #include "../Native_interface.hh" #include "../Quad_FIO.hh" class NativeFunction; static Fun_signature get_signature() { return SIG_Z_A_F2_B; } static Token help(ostream &out) { out << " Functions provided by MEM...\n" "\n" " Legend: e - error code (integer)\n" " h - file handle (integer)\n" " p - pointer (integer)\n" " i - integer\n" " s - string\n" "\n" " MEM[ 0] '' print this text\n" " Zp ← MEM[ 1] B1h B2i B3s mmap fd B1h, length B2i, mode B3s,\n" " B4i offset B4i\n" " mode: r read\n" " w write\n" " s shared (default private)\n" " h huge pages\n" " n noreserve\n" " p populate\n" " B3s default: rw private\n" " B1h = -1: anonymous map\n" " Ze ← MEM[ 2] B1p B2i munmap pointer B1p, length B2i\n" "\n" " Zi ← MEM[ 50] '' sizeof (float)\n" " Zi ← MEM[ 51] '' sizeof (double)\n" " Zi ← MEM[ 52] '' sizeof (long double)\n" " Zi ← MEM[ 53] '' sizeof (_Complex float)\n" " Zi ← MEM[ 54] '' sizeof (_Complex double)\n" " Zi ← MEM[ 55] '' sizeof (_Complex long double)\n" " Zi ← MEM[ 56] '' sizeof (char)\n" " Zi ← MEM[ 57] '' sizeof (short)\n" " Zi ← MEM[ 58] '' sizeof (int)\n" " Zi ← MEM[ 59] '' sizeof (long)\n" " Zi ← MEM[ 60] '' sizeof (long long)\n" " Zi ← MEM[ 61] '' sizeof (void *)\n" " Zi ← MEM[ 62] '' sizeof (char32_t)\n" "\n" " Z ← Ap MEM[100] Bi vector of Bi float at Ap\n" " Z ← Ap MEM[101] Bi vector of Bi double at Ap\n" " Z ← Ap MEM[102] Bi vector of Bi long double at Ap\n" " Z ← Ap MEM[103] Bi vector of Bi _Complex float at Ap\n" " Z ← Ap MEM[104] Bi vector of Bi _Complex double at Ap\n" " Z ← Ap MEM[105] Bi vector of Bi _Complex long double at Ap\n" " Z ← Ap MEM[106] Bi vector of Bi char int at Ap\n" " Z ← Ap MEM[107] Bi vector of Bi short from Ap\n" " Z ← Ap MEM[108] Bi vector of Bi int at Ap\n" " Z ← Ap MEM[109] Bi vector of Bi long at Ap\n" " Z ← Ap MEM[110] Bi vector of Bi long long at Ap\n" " Z ← Ap MEM[111] Bi vector of Bi (void *) at Ap\n" " Z ← Ap MEM[112] Bi vector of Bi char32_t at Ap\n" " Z ← Ap MEM[113] Bi vector of Bi char at Ap\n" "\n" " Ap MEM[150] B set Ap as float from B\n" " Ap MEM[151] B set Ap as double from B\n" " Ap MEM[152] B set Ap as long double from B\n" " Ap MEM[153] B set Ap as _Complex float from B\n" " Ap MEM[154] B set Ap as _Complex double from B\n" " Ap MEM[155] B set Ap as _Complex long double from B\n" " Ap MEM[156] B set Ap as char int from B\n" " Ap MEM[157] B set Ap as short from B\n" " Ap MEM[158] B set Ap as int from B\n" " Ap MEM[159] B set Ap as long from B\n" " Ap MEM[160] B set Ap as long long from B\n" " Ap MEM[161] B set Ap as (void *) from B\n" " Ap MEM[162] B set Ap as char32_t from B\n" " Ap MEM[163] B set Ap as char from B\n" ; /* msync [3] -- possible */ return Token(TOK_APL_VALUE1, Str0(LOC)); } static Token eval_B(Value_P B, const NativeFunction *caller) { return help(COUT); } static Token eval_AB(Value_P A, Value_P B, const NativeFunction *caller) { return help(COUT); } static Token eval_XB(Value_P X, Value_P B, const NativeFunction *caller) { int types[] = { sizeof (float), sizeof (double), sizeof (long double), sizeof (_Complex float), sizeof (_Complex double), sizeof (_Complex long double), sizeof (char), sizeof (short), sizeof (int), sizeof (long), sizeof (long long), sizeof (void *), sizeof (char32_t) }; if (B->get_rank() > 1) RANK_ERROR; if (X->get_rank() > 1) RANK_ERROR; int fn = X->get_ravel(0).get_near_int(); switch (fn) { case 0: return help(CERR); case 1: { /* mmap B1h B2i B3s */ int fd = B->get_ravel(0).get_near_int(); int l = B->get_ravel(1).get_near_int(); Value_P str = B->get_ravel(2).get_pointer_value(); UCS_string ucs(*str.get()); UTF8_string u(ucs); const char *s = u.c_str(); int flags = 0; int prot = 0; int shared = 0; int o = 0; if (fd == -1) flags = MAP_ANONYMOUS; else o = B->get_ravel(3).get_near_int(); for (; *s; ++s) switch (*s) { case 'r': prot |= PROT_READ; break; case 'w': prot |= PROT_WRITE; break; case 's': shared = 1; break; case 'h': flags |= MAP_HUGETLB; break; case 'n': flags |= MAP_NORESERVE; break; case 'p': flags |= MAP_POPULATE; break; } if (prot == 0) prot = PROT_READ | PROT_WRITE; flags |= shared ? MAP_SHARED : MAP_PRIVATE; void *p = mmap(NULL, l, prot, flags, fd, o); return Token(TOK_APL_VALUE1, IntScalar((long)p, LOC)); } case 2: { /* munmap B1p B2l */ void *p = (void *)(B->get_ravel(0).get_near_int()); int l = B->get_ravel(1).get_near_int(); int r = munmap(p, l); return Token(TOK_APL_VALUE1, IntScalar(r, LOC)); } case 50 ... 62: return Token(TOK_APL_VALUE1, IntScalar(types[fn-50], LOC)); } MORE_ERROR() << "bad function number " << fn << " in MEM eval_XB"; CERR << "MEM function number: " << fn << endl; DOMAIN_ERROR; return Token(TOK_APL_VALUE1, IntScalar(-1, LOC)); } static Token eval_AXB(Value_P A, Value_P X, Value_P B, const NativeFunction *caller) { if (A->get_rank() > 1) RANK_ERROR; if (B->get_rank() > 1) RANK_ERROR; if (X->get_rank() > 1) RANK_ERROR; int fn = X->get_ravel(0).get_near_int(); switch (fn) { case 0 ... 99: return eval_XB(X, B, caller); case 100: { float *p = (float *)(A->get_ravel(0).get_near_int()); int n = B->get_ravel(0).get_near_int(); Value_P Z(n, LOC); loop(i, n) new (Z->next_ravel()) FloatCell(p[i]); Z->check_value(LOC); return Token(TOK_APL_VALUE1, Z); } case 101: { double *p = (double *)(A->get_ravel(0).get_near_int()); int n = B->get_ravel(0).get_near_int(); Value_P Z(n, LOC); loop(i, n) new (Z->next_ravel()) FloatCell(p[i]); Z->check_value(LOC); return Token(TOK_APL_VALUE1, Z); } case 102: { long double *p = (long double *)(A->get_ravel(0).get_near_int()); int n = B->get_ravel(0).get_near_int(); Value_P Z(n, LOC); loop(i, n) new (Z->next_ravel()) FloatCell(p[i]); Z->check_value(LOC); return Token(TOK_APL_VALUE1, Z); } case 103: { _Complex float *p = (_Complex float *)(A->get_ravel(0).get_near_int()); int n = B->get_ravel(0).get_near_int(); Value_P Z(n, LOC); loop(i, n) new (Z->next_ravel()) ComplexCell(creal(p[i]), cimag(p[i])); Z->check_value(LOC); return Token(TOK_APL_VALUE1, Z); } case 104: { _Complex double *p = (_Complex double *)(A->get_ravel(0).get_near_int()); int n = B->get_ravel(0).get_near_int(); Value_P Z(n, LOC); loop(i, n) new (Z->next_ravel()) ComplexCell(creal(p[i]), cimag(p[i])); Z->check_value(LOC); return Token(TOK_APL_VALUE1, Z); } case 105: { _Complex long double *p = (_Complex long double *)(A->get_ravel(0).get_near_int()); int n = B->get_ravel(0).get_near_int(); Value_P Z(n, LOC); loop(i, n) new (Z->next_ravel()) ComplexCell(creal(p[i]), cimag(p[i])); Z->check_value(LOC); return Token(TOK_APL_VALUE1, Z); } case 106: { char *p = (char *)(A->get_ravel(0).get_near_int()); int n = B->get_ravel(0).get_near_int(); Value_P Z(n, LOC); loop(i, n) new (Z->next_ravel()) IntCell(p[i]); Z->check_value(LOC); return Token(TOK_APL_VALUE1, Z); } case 107: { short *p = (short *)(A->get_ravel(0).get_near_int()); int n = B->get_ravel(0).get_near_int(); Value_P Z(n, LOC); loop(i, n) new (Z->next_ravel()) IntCell(p[i]); Z->check_value(LOC); return Token(TOK_APL_VALUE1, Z); } case 108: { int *p = (int *)(A->get_ravel(0).get_near_int()); int n = B->get_ravel(0).get_near_int(); Value_P Z(n, LOC); loop(i, n) new (Z->next_ravel()) IntCell(p[i]); Z->check_value(LOC); return Token(TOK_APL_VALUE1, Z); } case 109: { long *p = (long *)(A->get_ravel(0).get_near_int()); int n = B->get_ravel(0).get_near_int(); Value_P Z(n, LOC); loop(i, n) new (Z->next_ravel()) IntCell(p[i]); Z->check_value(LOC); return Token(TOK_APL_VALUE1, Z); } case 110: { long long *p = (long long *)(A->get_ravel(0).get_near_int()); int n = B->get_ravel(0).get_near_int(); Value_P Z(n, LOC); loop(i, n) new (Z->next_ravel()) IntCell(p[i]); Z->check_value(LOC); return Token(TOK_APL_VALUE1, Z); } case 111: { void **p = (void **)(A->get_ravel(0).get_near_int()); int n = B->get_ravel(0).get_near_int(); Value_P Z(n, LOC); loop(i, n) new (Z->next_ravel()) IntCell((long)(p[i])); Z->check_value(LOC); return Token(TOK_APL_VALUE1, Z); } case 112: { char32_t *p = (char32_t *)(A->get_ravel(0).get_near_int()); int n = B->get_ravel(0).get_near_int(); Value_P Z(n, LOC); loop(i, n) new (Z->next_ravel()) CharCell((Unicode)(p[i] ? p[i] : ' ')); Z->check_value(LOC); return Token(TOK_APL_VALUE1, Z); } case 113: { char *p = (char *)(A->get_ravel(0).get_near_int()); int n = B->get_ravel(0).get_near_int(); Value_P Z(n, LOC); loop(i, n) new (Z->next_ravel()) CharCell((Unicode)(p[i] ? p[i] : ' ')); Z->check_value(LOC); return Token(TOK_APL_VALUE1, Z); } case 150: { float *p = (float *)(A->get_ravel(0).get_near_int()); int n = B->get_cols(); loop(i, n) p[i] = B->get_ravel(i).get_real_value(); return Token(TOK_APL_VALUE1, Str0(LOC)); } case 151: { double *p = (double *)(A->get_ravel(0).get_near_int()); int n = B->get_cols(); loop(i, n) p[i] = B->get_ravel(i).get_real_value(); return Token(TOK_APL_VALUE1, Str0(LOC)); } case 152: { long double *p = (long double *)(A->get_ravel(0).get_near_int()); int n = B->get_cols(); loop(i, n) p[i] = B->get_ravel(i).get_real_value(); return Token(TOK_APL_VALUE1, Str0(LOC)); } case 153: { _Complex float *p = (_Complex float *)(A->get_ravel(0).get_near_int()); int n = B->get_cols(); loop(i, n) p[i] = B->get_ravel(i).get_real_value() + I * B->get_ravel(i).get_imag_value(); return Token(TOK_APL_VALUE1, Str0(LOC)); } case 154: { _Complex double *p = (_Complex double *)(A->get_ravel(0).get_near_int()); int n = B->get_cols(); loop(i, n) p[i] = B->get_ravel(i).get_real_value() + I * B->get_ravel(i).get_imag_value(); return Token(TOK_APL_VALUE1, Str0(LOC)); } case 155: { _Complex long double *p = (_Complex long double *)(A->get_ravel(0).get_near_int()); int n = B->get_cols(); loop(i, n) p[i] = B->get_ravel(i).get_real_value() + I * B->get_ravel(i).get_imag_value(); return Token(TOK_APL_VALUE1, Str0(LOC)); } case 156: { char *p = (char *)(A->get_ravel(0).get_near_int()); int n = B->get_cols(); loop(i, n) p[i] = B->get_ravel(i).get_near_int(); return Token(TOK_APL_VALUE1, Str0(LOC)); } case 157: { short *p = (short *)(A->get_ravel(0).get_near_int()); int n = B->get_cols(); loop(i, n) p[i] = B->get_ravel(i).get_near_int(); return Token(TOK_APL_VALUE1, Str0(LOC)); } case 158: { int *p = (int *)(A->get_ravel(0).get_near_int()); int n = B->get_cols(); loop(i, n) p[i] = B->get_ravel(i).get_near_int(); return Token(TOK_APL_VALUE1, Str0(LOC)); } case 159: { long *p = (long *)(A->get_ravel(0).get_near_int()); int n = B->get_cols(); loop(i, n) p[i] = B->get_ravel(i).get_near_int(); return Token(TOK_APL_VALUE1, Str0(LOC)); } case 160: { long long *p = (long long *)(A->get_ravel(0).get_near_int()); int n = B->get_cols(); loop(i, n) p[i] = B->get_ravel(i).get_near_int(); return Token(TOK_APL_VALUE1, Str0(LOC)); } case 161: { void **p = (void **)(A->get_ravel(0).get_near_int()); int n = B->get_cols(); loop(i, n) p[i] = (void *)(B->get_ravel(i).get_near_int()); return Token(TOK_APL_VALUE1, Str0(LOC)); } case 162: { char32_t *p = (char32_t *)(A->get_ravel(0).get_near_int()); int n = B->get_cols(); loop(i, n) p[i] = (char32_t)(B->get_ravel(i).get_char_value()); return Token(TOK_APL_VALUE1, Str0(LOC)); } case 163: { char *p = (char *)(A->get_ravel(0).get_near_int()); int n = B->get_cols(); loop(i, n) p[i] = (char)(B->get_ravel(i).get_char_value()); return Token(TOK_APL_VALUE1, Str0(LOC)); } } MORE_ERROR() << "bad function number " << fn << " in MEM eval_AXB"; CERR << "MEM function number: " << fn << endl; DOMAIN_ERROR; return Token(TOK_APL_VALUE1, IntScalar(-1, LOC)); } extern "C" void *get_function_mux(const char *function_name) { if (!strcmp(function_name, "get_signature")) return (void *)&get_signature; if (!strcmp(function_name, "eval_B")) return (void *)&eval_B; if (!strcmp(function_name, "eval_AB")) return (void *)&eval_AB; if (!strcmp(function_name, "eval_XB")) return (void *)&eval_XB; if (!strcmp(function_name, "eval_AXB")) return (void *)&eval_AXB; return 0; }