GithubHelp home page GithubHelp logo

ukrbublik / shm-typed-array Goto Github PK

View Code? Open in Web Editor NEW
69.0 4.0 10.0 106 KB

IPC shared memory for NodeJs. Use as Buffer or TypedArray.

License: MIT License

Python 0.68% JavaScript 30.82% C++ 65.40% TypeScript 3.10%
ipc shm nodejs shared-memory buffer sharedarraybuffer typescript

shm-typed-array's Introduction

IPC shared memory for Node.js
Use as Buffer or TypedArray
Supports System V and POSIX shared memory
npm travis

Install

$ npm install shm-typed-array

Windows is not supported.

System V vs POSIX

Versions 0.0.* support only System V memory segments.
Starting from version 0.1.0 POSIX memory objects are also supported.

System V is the classic way to use shared memory, stores IPC objects internally in the kernel.
POSIX is newer, but not fully supported in MacOS, uses the file system interface.

To create POSIX memory objects, use string parameter key in API.
Eg. shm.create(100, 'Buffer', '/test') will create virtual file /dev/shm/test in tmpfs for Linix.

To create System V memory segment, use numeric parameter key in API.
Eg. shm.create(100, 'Buffer', 1234) or shm.create(100) to autogenerate key.

API

shm.create (count, typeKey, key?, perm?)

Create shared memory segment/object.
count - number of elements (not bytes),
typeKey - type of elements ('Buffer' by default, see list below),
key - integer/null to create System V memory segment, or string to create POSIX memory object,
perm - permissions flag (default is 660).
Returns shared memory Buffer or descendant of TypedArray object, class depends on param typeKey.
Or returns null if shm already exists with provided key.
For System V: returned object has property key - integer key of created System V shared memory segment, to use in shm.get(key).
For POSIX: shared memory objects are not automatically destroyed. You should call shm.destroy(key) manually on process cleanup or if you don't need the object anymore.

shm.get (key, typeKey)

Get created shared memory segment/object by key.
Returns null if shm not exists with provided key.

shm.detach (key, forceDestroy?)

Detach shared memory segment/object.
For System V: If there are no other attaches for a segment, it will be destroyed automatically (even if forceDestroy is not true).
For POSIX: Unlike System V segments, POSIX object will not be destroyed automatically. You need to destroy it manually by providing true to forceDestroy argument or using shm.destroy(key).

shm.destroy (key)

Destroy shared memory segment/object.
Same as shm.detach(key, true)

shm.detachAll ()

Detach all created shared memory segments and objects.
Will be automatically called on process exit, see Cleanup.

shm.getTotalSize()

Get total size of all used (mapped) shared memory in bytes.

shm.getTotalCreatedSize()

Get total size of all created shared memory in bytes.

shm.LengthMax

Max length of shared memory segment (count of elements, not bytes)
2^31 for 64bit, 2^30 for 32bit

Types:

shm.BufferType = {
	'Buffer': shm.SHMBT_BUFFER,
	'Int8Array': shm.SHMBT_INT8,
	'Uint8Array': shm.SHMBT_UINT8,
	'Uint8ClampedArray': shm.SHMBT_UINT8CLAMPED,
	'Int16Array': shm.SHMBT_INT16,
	'Uint16Array': shm.SHMBT_UINT16,
	'Int32Array': shm.SHMBT_INT32,
	'Uint32Array': shm.SHMBT_UINT32,
	'Float32Array': shm.SHMBT_FLOAT32,
	'Float64Array': shm.SHMBT_FLOAT64,
};

Cleanup

This library does cleanup of created SHM segments/objects only on normal exit of process, see exit event.
If you want to do cleanup on terminate signals like SIGINT, SIGTERM, please use node-cleanup / node-death and add code to exit handlers:

shm.detachAll();

Also note that POSIX shared memory objects are not automatically destroyed. You should call shm.destroy('/your_name') manually if you don't need it anymore.

Usage

See example.js

Usage of memory segments:

const cluster = require('cluster');
const shm = require('shm-typed-array');

var buf, arr;
if (cluster.isMaster) {
	buf = shm.create(4096); //4KB
	arr = shm.create(1000000*100, 'Float32Array'); //100M floats
	buf[0] = 1;
	arr[0] = 10.0;
	console.log('[Master] Typeof buf:', buf.constructor.name,
		'Typeof arr:', arr.constructor.name);
	
	var worker = cluster.fork();
	worker.on('online', function() {
		this.send({ msg: 'shm', bufKey: buf.key, arrKey: arr.key });
		var i = 0;
		setInterval(function() {
			buf[0] += 1;
			arr[0] /= 2;
			console.log(i + ' [Master] Set buf[0]=', buf[0],
				' arr[0]=', arr ? arr[0] : null);
			i++;
			if (i == 5) {
				groupSuicide();
			}
		}, 500);
	});
} else {
	process.on('message', function(data) {
		var msg = data.msg;
		if (msg == 'shm') {
			buf = shm.get(data.bufKey);
			arr = shm.get(data.arrKey, 'Float32Array');
			console.log('[Worker] Typeof buf:', buf.constructor.name,
				'Typeof arr:', arr.constructor.name);
			var i = 0;
			setInterval(function() {
				console.log(i + ' [Worker] Get buf[0]=', buf[0],
					' arr[0]=', arr ? arr[0] : null);
				i++;
				if (i == 2) {
					shm.detach(data.arrKey);
					arr = null; //otherwise process will drop
				}
			}, 500);
		} else if (msg == 'exit') {
			process.exit();
		}
	});
}

function groupSuicide() {
	if (cluster.isMaster) {
		for (var id in cluster.workers) {
		    cluster.workers[id].send({ msg: 'exit'});
		    cluster.workers[id].destroy();
		}
		process.exit();
	}
}

Output:

[Master] Typeof buf: Buffer Typeof arr: Float32Array
[Worker] Typeof buf: Buffer Typeof arr: Float32Array
0 [Master] Set buf[0]= 2  arr[0]= 5
0 [Worker] Get buf[0]= 2  arr[0]= 5
1 [Master] Set buf[0]= 3  arr[0]= 2.5
1 [Worker] Get buf[0]= 3  arr[0]= 2.5
2 [Master] Set buf[0]= 4  arr[0]= 1.25
2 [Worker] Get buf[0]= 4  arr[0]= null
3 [Master] Set buf[0]= 5  arr[0]= 0.625
3 [Worker] Get buf[0]= 5  arr[0]= null
4 [Master] Set buf[0]= 6  arr[0]= 0.3125
shm segments destroyed: 2

shm-typed-array's People

Contributors

a0000778 avatar drydemon avatar gwillz avatar parisholley avatar trxcllnt avatar ukrbublik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

shm-typed-array's Issues

I'd like to use a fixed key.

Hi.

Thank to develop and open this module.

In my project, I need to use a fixed key not a generated key.
So I wanna suggest to change create method like following.
I added defkey parameter.
When it is not defined, the key would be generated as it was.
But if it is given, the key would be set defkey value.

/**
 * Create shared memory segment
 * @param {int} count - number of elements
 * @param {string} typeKey - see keys of BufferType
 * @param {int} defkey - default key
 * @return {mixed} shared memory buffer/array object
 *  Class depends on param typeKey: Buffer or descendant of TypedArray
 *  Return object has property 'key' - integer key of created shared memory segment
 */
function create(count, typeKey, defkey) {
    if (typeKey === undefined)
        typeKey = 'Buffer';
    if (BufferType[typeKey] === undefined)
        throw new Error("Unknown type key " + typeKey);
    var type = BufferType[typeKey];

    if (!(Number.isSafeInteger(count) && count >= lengthMin && count <= lengthMax))
        throw new RangeError('Count should be ' + lengthMin + ' .. ' + lengthMax);
    let key, res;
    do {
        if (defkey === undefined)
            key = _keyGen();
        else
            key = defkey;
        res = shm.get(key, count, shm.IPC_CREAT|shm.IPC_EXCL|perm, 0, type);
    } while(!res);
    res.key = key;
    return res;
}

version change in v8 ArrayBuffer

So, I am the guy who used your module as a spring board to create a shared LRU, which works nicely for the most part.

But, I started running into some issues putting code onto tiny boxes, e.g. Rock64 and ZeroPi. So, I had problems with versions of python for gyp. Then, I noticed that node.js is moving towards cmake with cmake-js as a helper for node modules. I ran into troubles with version just because I didn't have a fairly new Linux on the devices.

But, I got one box relatively up to date, and I got a compile problem. So, V8 has changed its header for ArrayBuffer::New. There a no four parameters versions anymore. You now have to use a BackingStore. The old call was marked for deprecation in V8 8... Maybe sooner, but did not check all versions. The BackingStore is required in at least version 9.

So, you may want to upgrade to support newer uses of your code.

Question about memory layout

Hi, and thanks for this module! I am having it inter-operate with a C program using the POSIX shm_* functions. I have noticed that, from the point of view of C, it seems that the module considers the data to start two elements past the initial shared memory address. It also seems that it uses the first element to store the number of elements. Is this correct? Is there a use for the second element of shared memory?

If I just take into account this 2-element offset, everything seems to work fine, I can create shared memory in C or JS (under node), and read from and write to it from both C and JS.

Thanks!

Attach'ing problem relevant with flags IPC_CREAT | IPC_EXCL

There is no attach method for outside of node.js environments. I created a SHM in C++ but the node cant attach with it. To have access to shm, it must have created it own.

Another problem is: I'm creating a shm with a key and can reading in same execution session but I start a new execution with same key to read previous data then create method returns null and failing. Because of theresi is no attach method and create method already has IPC_EXCL flag.

Please your attention:

res = shm.get(key, count, shm.IPC_CREAT|shm.IPC_EXCL|perm, 0, type);

I think that if second flag (IPC_EXCL) will be ommitted from create method then the problem above solved and the create method can create a new and can attach already one.

Also, if we consider the server environment safe, the permissions must be set to 666 for another program to read and write.

Ref: https://man7.org/linux/man-pages/man2/shmget.2.html

Error: Too many open files

I use shm at MacOS,is the library support windows?this is the code.
Look like the datas is saved to file,so is not the data in the memory?and how can I correct to use?


if (this.shmBuffer != null) {
    Buffer.from(data).copy(this.shmBuffer)
    this.worker.send( {
          key:this.shmBuffer.key,
          length:data.length
    })
}

Uncaught exception...
Error: Too many open files
    at Object.get (/Users/ymr/kaochong/klive-teacher/teacher-package/node_modules/shm-typed-array/index.js:108:16)
    at Socket.onMessage (/Users/ymr/kaochong/klive-teacher/teacher-package/src/base-sdk/net/socket/remote-socket.ts:94:39)
    at process.<anonymous> (/Users/ymr/kaochong/klive-teacher/teacher-package/src/base-sdk/net/socket/remote-socket.ts:110:18)
    at process.emit (events.js:210:5)
    at process.emit (/Users/ymr/kaochong/klive-teacher/teacher-package/node_modules/source-map-support/source-map-support.js:485:21)
    at emit (internal/child_process.js:876:12)
    at processTicksAndRejections (internal/process/task_queues.js:81:21)
Uncaught exception...
Error [ERR_IPC_CHANNEL_CLOSED]: Channel closed
    at ChildProcess.target.send (internal/child_process.js:678:16)
    at SocketImp../src/base-sdk/net/socket/socket.ts.SocketImp.sendToWorkerFromBuffer (http://localhost:3000/main_window/index.js:54502:25)
    at SocketImp../src/base-sdk/net/socket/socket.ts.SocketImp.write (http://localhost:3000/main_window/index.js:54489:14)
    at http://localhost:3000/main_window/index.js:54082:29

function get doesnt set shm_size and always returns 1024 array

SHM_arr = shm.create(4, 'Uint8Array', SHM_SEGMET_KEY);
SHM_arr[0] = Math.floor(Math.random() * 255);
SHM_arr[1] = Math.floor(Math.random() * 255);
node.log(SHM_arr);
SHM_arr = shm.get(SHM_SEGMET_KEY, 'Uint8Array');
node.log(SHM_arr);

Outputs:

16 Jun 05:38:13 - [info] [ss963-driver:4a2c9bf7.0a86dc] 114,50,0,0
16 Jun 05:38:13 - [info] [ss963-driver:4a2c9bf7.0a86dc] 114,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

There are the functions below. In "function create", shm.get sets the shm_size but "function get" doesnt so returns 1024 bytes length array as seen above.

/**

  • Create shared memory segment
  • @param {int} count - number of elements
  • @param {string} typeKey - see keys of BufferType
  • @param {int/null} key - integer key of shared memory segment, or null to autogenerate
  • @return {mixed/null} shared memory buffer/array object, or null on error
  • Class depends on param typeKey: Buffer or descendant of TypedArray
  • Return object has property 'key' - integer key of created shared memory segment
    /
    function create(count, typeKey /
    = 'Buffer'/, key /= null*/) {
    if (typeKey === undefined)
    typeKey = 'Buffer';
    if (key === undefined)
    key = null;
    if (BufferType[typeKey] === undefined)
    throw new Error("Unknown type key " + typeKey);
    if (key !== null) {
    if (!(Number.isSafeInteger(key) && key >= keyMin && key <= keyMax))
    throw new RangeError('Shm key should be ' + keyMin + ' .. ' + keyMax);
    }
    var type = BufferType[typeKey];
    //var size1 = BufferTypeSizeof[typeKey];
    //var size = size1 * count;
    if (!(Number.isSafeInteger(count) && count >= lengthMin && count <= lengthMax))
    throw new RangeError('Count should be ' + lengthMin + ' .. ' + lengthMax);
    let res;
    if (key) {
    res = shm.get(key, count, shm.IPC_CREAT|shm.IPC_EXCL|perm, 0, type);
    } else {
    do {
    key = _keyGen();
    res = shm.get(key, count, shm.IPC_CREAT|shm.IPC_EXCL|perm, 0, type);
    } while(!res);
    }
    if (res) {
    res.key = key;
    }
    return res;
    }

/**

  • Get shared memory segment
  • @param {int} key - integer key of shared memory segment
  • @param {string} typeKey - see keys of BufferType
  • @return {mixed/null} shared memory buffer/array object, see create(), or null on error
    /
    function get(key, typeKey /
    = 'Buffer'*/) {
    if (typeKey === undefined)
    typeKey = 'Buffer';
    if (BufferType[typeKey] === undefined)
    throw new Error("Unknown type key " + typeKey);
    var type = BufferType[typeKey];
    if (!(Number.isSafeInteger(key) && key >= keyMin && key <= keyMax))
    throw new RangeError('Shm key should be ' + keyMin + ' .. ' + keyMax);
    let res = shm.get(key, 0, 0, 0, type);
    if (res) {
    res.key = key;
    }
    return res;
    }

Nan is vulnerable to DOS

The current version of Nan (2.13.2) is vulnerable because of posux and should not be used.

It should be updated to 2.18.0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.