locka99 / opcua

A client and server implementation of the OPC UA specification written in Rust
Mozilla Public License 2.0
496 stars 131 forks source link

[Help] Deadlock while writing to variable? #124

Closed jigar88 closed 3 years ago

jigar88 commented 3 years ago

I have server side running with some variables. I am trying to update the variable value but it results in deadlock in thread. How can I update the variable value with RwLockWriteGuard presence ?

I have set my server and address space as shown below.

let opc_server = Server::new(ServerConfig::load(&PathBuf::from("/tmp/server.conf")).unwrap());
let server = Arc::new(RwLock::new(opc_server));
let address_space = server.address_space();
let mut address_space = address_space.write().unwrap();
let now = DateTime::now();
address_space.set_variable_value(&NodeId, valueToUpdate, &now, &now);

this results in

thread '<unnamed>' panicked at 'rwlock write lock would result in deadlock', /build/rustc-UHkz09/rustc-1.47.0+dfsg1+llvm/library/std/src/sys/unix/rwlock.rs:86:13
jigar88 commented 3 years ago

this might be causing by other piece of code. Not related to opcua code.

locka99 commented 3 years ago

Does the simple_server have this same issue?

In general also it's a good idea to minimize locks. Use read locks if a read lock will do and use scopes to release them as soon as possible. e.g. release the server as soon as you have the address space from it like this.

let server = Arc::new(RwLock::new(opc_server));
let address_space = {
   let server = server.read().unwrap();
   server.address_space()
};
jigar88 commented 3 years ago
let server = Arc::new(RwLock::new(opc_server));
let address_space = {
   let server = server.read().unwrap();
   server.address_space()
};

This will return address_space as function so can I reuse it as an address space to pass an parameter for later function or I need to recreate it ?

locka99 commented 3 years ago

That block unlocks the server, calls the function address_space(), implicitly releases the lock, and returns a Arc<RwLock> to the outer let statement where it is assigned.

Try the simple-server too and see if it suffers the issue you are seeing since it also uses set_variable_value()

jigar88 commented 3 years ago

I think deadlock happens because of the other code not because of opcua code. I am digging in.

is there a way to get server status in the tag for monitoring, like weather server is started or running or broken? Or I need to use server status node defined in the server state to get the server status ? In python there is a function like server.is_running() , is there anything equivalent available ?

also I tried to use server info in the Ignition client but most of the nodes are null and not showing data. image