Multi-Thread 4--- Lock & Conditions

本文探讨了并发编程中读写锁与条件变量的使用,通过实例展示了如何利用它们实现线程间的同步与协调,包括数据获取、更新及通知机制。同时,介绍了使用Lock和条件变量创建受限缓冲区的方法,以及在生产者消费者模型中的应用。

1. Using reading and writing lock

Reading lock can make a data be read concurrently, but block writing thread. writeLock block all other reading and writing thread.
public class LockDemo {

	private Map<String, Object> cacheData = new HashMap<String, Object>();// this is data
	private ReadWriteLock rwl = new ReentrantReadWriteLock();
	
	//this method to get data, if not in the map, we should get access to DB, need write it back to map
	public Object getData(String key){
		rwl.readLock().lock();
		try{
			Object cache = cacheData.get(key);
			if(cache == null){
				rwl.readLock().unlock();
				rwl.writeLock().lock(); //other running read thread will lock here
				try{
					if(cache == null){//use this sentanse again to make sure other thread won't wirte again,after the
									  //first thread wirte the data back.
						cache = "aaaaa"; // go to DB to get data. 
					}
				}finally{
					rwl.writeLock().unlock();	
				}
				rwl.readLock().lock();
			}
			return cache;
		}finally{
			rwl.readLock().unlock();
		}
		
		
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}
}

A easier way to do this is just add synchronized key word in the definition of method.

2. Conditions

condition = lock.newCondition();
condition has method like condition.await(), and condition.signal(). it has the same function as object.wait() and object.notify(). But condition is more powerful, for it can create many conditions based  on one Lock().

For example, if we want to let thread 1, run 10 times, then thread 2 run 20 times, and then thread2 run 100 times, then goes back to thread 1. to make this loop run 30 times. we can't realize it by simply using wait() and notify. we can use Lock and conditions instead.

Business.java
public class Business {

	//lock and its conditions
	private Lock lock = new ReentrantLock();
	Condition conjob1 = lock.newCondition(); //condition that job1 should start
	Condition conjob2 = lock.newCondition(); //condition that job2 should start
	Condition conjob3 = lock.newCondition(); //condition that job3 should start
	private int flag = 1;//by default, the first job start first
	
	
	//job1, the thread runs 10 times
	public void job1(){
		lock.lock();
		try{
			while(flag != 1){ //first job should wait
				conjob1.await();
			}
			for(int i=1;i<=10;i++){
				System.out.println("job 1------------- "+i);
			}
			
			//after finish job1, it should notify job2
			flag = 2;
			conjob2.signal();
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
	}
	
	//job2, the thread runs 20 times
	public void job2(){
		lock.lock();
		try{
			while(flag != 2){ //second job should wait
				conjob2.await();
			}
			for(int i=1;i<=20;i++){
				System.out.println("job 2------------- "+i);
			}
			//after finish job2, it should notify job3
			flag = 3;
			conjob3.signal();
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
	}
	
	//job3, the thread runs 30 times
	public void job3(){
		lock.lock();
		try{
			while(flag != 3){ //third job should wait
				conjob3.await();
			}
			for(int i=1;i<=30;i++){
				System.out.println("job 3------------- "+i);
			}
			//after finish job1, it should notify job2
			flag = 1;
			conjob1.signal();
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
	}
}

main.java
static Business business = new Business();
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		Runnable run1 = new Runnable(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				for(int i=1;i<30;i++){
					business.job1();
				}
				
			}
		};
		//runable2
		Runnable run2 = new Runnable(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				for(int i=1;i<30;i++){
					business.job2();
				}
			}
		};
		
		Runnable run3 = new Runnable(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				for(int i=1;i<30;i++){
					business.job3();
				}
			}
		};
		Thread t1 = new Thread(run1);
		Thread t2 = new Thread(run2);
		Thread t3 = new Thread(run3);
		t1.start();
		t2.start();
		t3.start();
		
	}
}

2.2 using Lock and condition to create a bundedBuffer( producer and consumer model)

Producers produce tokens at a solid speed and put the token into an array, and the consumer take out a token at a time and consume it. Create such a bundebuffer so that the producer thread will wait while the array is full, and the consumer thread will also wait while the array is empty.

 class BoundedBuffer {
   final Lock lock = new ReentrantLock(); //one lock
   final Condition notFull  = lock.newCondition(); //condition to see if it's full
   final Condition notEmpty = lock.newCondition(); //condition to see if it's empty

   final Object[] items = new Object[100];
   int putptr, takeptr, count;

   public void put(Object x) throws InterruptedException {
     lock.lock();
     try {
       while (count == items.length)  //if it's full
         notFull.await();  //not full conditon doesn't apply, so it wait
       items[putptr] = x;  //if it's not full, we put this token into a place
       if (++putptr == items.length) putptr = 0; //if put pointer goes to the end, we move it to the begining
       ++count;  //after put, the total amount would increase
       notEmpty.signal(); //signal a not empty condition, if there are any, becase we put one inside, we can make it not empty
     } finally {
       lock.unlock();  //unlock() in case there are some exception thrown
     }
   }

   public Object take() throws InterruptedException {
     lock.lock();
     try {
       while (count == 0)   //if it's empty, we can't take, so we have to wait
         notEmpty.await();  // so notEmpty make us waiting here
       Object x = items[takeptr]; //otherwise ,we take one item out of the array
       if (++takeptr == items.length) takeptr = 0; //if the take point goes to the end, we move it to the front
       --count;  //after take, the total amount would decrease one
       notFull.signal(); // notify the not full condition
       return x;
     } finally {
       lock.unlock();
     }
   }
 }





内容概要:本文档介绍了基于3D FDTD(时域有限差分)方法在MATLAB平台上对微带线馈电的矩形天线进行仿真分析的技术方案,重点在于模拟超MATLAB基于3D FDTD的微带线馈矩形天线分析[用于模拟超宽带脉冲通过线馈矩形天线的传播,以计算微带结构的回波损耗参数]宽带脉冲信号通过天线结构的传播过程,并计算微带结构的回波损耗参数(S11),以评估天线的匹配性能和辐射特性。该方法通过建立三维电磁场模型,精确求解麦克斯韦方程组,适用于高频电磁仿真,能够有效分析天线在宽频带内的响应特性。文档还提及该资源属于一个涵盖多个科研方向的综合性MATLAB仿真资源包,涉及通信、信号处理、电力系统、机器学习等多个领域。; 适合人群:具备电磁场与微波技术基础知识,熟悉MATLAB编程及数值仿真的高校研究生、科研人员及通信工程领域技术人员。; 使用场景及目标:① 掌握3D FDTD方法在天线仿真中的具体实现流程;② 分析微带天线的回波损耗特性,优化天线设计参数以提升宽带匹配性能;③ 学习复杂电磁问题的数值建模与仿真技巧,拓展在射频与无线通信领域的研究能力。; 阅读建议:建议读者结合电磁理论基础,仔细理解FDTD算法的离散化过程和边界条件设置,运行并调试提供的MATLAB代码,通过调整天线几何尺寸和材料参数观察回波损耗曲线的变化,从而深入掌握仿真原理与工程应用方法。
/**************************************************************************** * drivers/sensors/sensor.c * * SPDX-License-Identifier: Apache-2.0 * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * &quot;License&quot;); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an &quot;AS IS&quot; BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include &lt;nuttx/config.h&gt; #include &lt;sys/types.h&gt; #include &lt;stdbool.h&gt; #include &lt;stdio.h&gt; #include &lt;string.h&gt; #include &lt;assert.h&gt; #include &lt;errno.h&gt; #include &lt;debug.h&gt; #include &lt;poll.h&gt; #include &lt;fcntl.h&gt; #include &lt;nuttx/list.h&gt; #include &lt;nuttx/kmalloc.h&gt; #include &lt;nuttx/circbuf.h&gt; #include &lt;nuttx/mutex.h&gt; #include &lt;nuttx/sensors/sensor.h&gt; #include &lt;nuttx/lib/lib.h&gt; /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /* Device naming ************************************************************/ #define ROUND_DOWN(x, y) (((x) / (y)) * (y)) #define DEVNAME_FMT &quot;/dev/uorb/sensor_%s%s%d&quot; #define DEVNAME_UNCAL &quot;_uncal&quot; #define TIMING_BUF_ESIZE (sizeof(uint32_t)) /**************************************************************************** * Private Types ****************************************************************************/ struct sensor_axis_map_s { int8_t src_x; int8_t src_y; int8_t src_z; int8_t sign_x; int8_t sign_y; int8_t sign_z; }; /* This structure describes sensor meta */ struct sensor_meta_s { size_t esize; FAR char *name; }; typedef enum sensor_role_e { SENSOR_ROLE_NONE, SENSOR_ROLE_WR, SENSOR_ROLE_RD, SENSOR_ROLE_RDWR, } sensor_role_t; /* This structure describes user info of sensor, the user may be * advertiser or subscriber */ struct sensor_user_s { /* The common info */ struct list_node node; /* Node of users list */ struct pollfd *fds; /* The poll structure of thread waiting events */ sensor_role_t role; /* The is used to indicate user&#39;s role based on open flags */ bool changed; /* This is used to indicate event happens and need to * asynchronous notify other users */ unsigned int event; /* The event of this sensor, eg: SENSOR_EVENT_FLUSH_COMPLETE. */ bool flushing; /* The is used to indicate user is flushing */ sem_t buffersem; /* Wakeup user waiting for data in circular buffer */ size_t bufferpos; /* The index of user generation in buffer */ /* The subscriber info * Support multi advertisers to subscribe their own data when they * appear in dual role */ struct sensor_ustate_s state; }; /* This structure describes the state of the upper half driver */ struct sensor_upperhalf_s { FAR struct sensor_lowerhalf_s *lower; /* The handle of lower half driver */ struct sensor_state_s state; /* The state of sensor device */ struct circbuf_s timing; /* The circular buffer of generation */ struct circbuf_s buffer; /* The circular buffer of data */ rmutex_t lock; /* Manages exclusive access to file operations */ struct list_node userlist; /* List of users */ }; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ static void sensor_pollnotify(FAR struct sensor_upperhalf_s *upper, pollevent_t eventset, sensor_role_t role); static int sensor_open(FAR struct file *filep); static int sensor_close(FAR struct file *filep); static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer, size_t buflen); static ssize_t sensor_write(FAR struct file *filep, FAR const char *buffer, size_t buflen); static int sensor_ioctl(FAR struct file *filep, int cmd, unsigned long arg); static int sensor_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup); static ssize_t sensor_push_event(FAR void *priv, FAR const void *data, size_t bytes); /**************************************************************************** * Private Data ****************************************************************************/ static const struct sensor_axis_map_s g_remap_tbl[] = { { 0, 1, 2, 1, 1, 1 }, /* P0 */ { 1, 0, 2, 1, -1, 1 }, /* P1 */ { 0, 1, 2, -1, -1, 1 }, /* P2 */ { 1, 0, 2, -1, 1, 1 }, /* P3 */ { 0, 1, 2, -1, 1, -1 }, /* P4 */ { 1, 0, 2, -1, -1, -1 }, /* P5 */ { 0, 1, 2, 1, -1, -1 }, /* P6 */ { 1, 0, 2, 1, 1, -1 }, /* P7 */ }; static const struct sensor_meta_s g_sensor_meta[] = { {0, NULL}, {sizeof(struct sensor_accel), &quot;accel&quot;}, {sizeof(struct sensor_mag), &quot;mag&quot;}, {sizeof(struct sensor_orientation), &quot;orientation&quot;}, {sizeof(struct sensor_gyro), &quot;gyro&quot;}, {sizeof(struct sensor_light), &quot;light&quot;}, {sizeof(struct sensor_baro), &quot;baro&quot;}, {sizeof(struct sensor_noise), &quot;noise&quot;}, {sizeof(struct sensor_prox), &quot;prox&quot;}, {sizeof(struct sensor_rgb), &quot;rgb&quot;}, {sizeof(struct sensor_accel), &quot;linear_accel&quot;}, {sizeof(struct sensor_rotation), &quot;rotation&quot;}, {sizeof(struct sensor_humi), &quot;humi&quot;}, {sizeof(struct sensor_temp), &quot;temp&quot;}, {sizeof(struct sensor_pm25), &quot;pm25&quot;}, {sizeof(struct sensor_pm1p0), &quot;pm1p0&quot;}, {sizeof(struct sensor_pm10), &quot;pm10&quot;}, {sizeof(struct sensor_event), &quot;motion_detect&quot;}, {sizeof(struct sensor_event), &quot;step_detector&quot;}, {sizeof(struct sensor_step_counter), &quot;step_counter&quot;}, {sizeof(struct sensor_ph), &quot;ph&quot;}, {sizeof(struct sensor_hrate), &quot;hrate&quot;}, {sizeof(struct sensor_event), &quot;tilt_detector&quot;}, {sizeof(struct sensor_event), &quot;wake_gesture&quot;}, {sizeof(struct sensor_event), &quot;glance_gesture&quot;}, {sizeof(struct sensor_event), &quot;pickup_gesture&quot;}, {sizeof(struct sensor_event), &quot;wrist_tilt&quot;}, {sizeof(struct sensor_orientation), &quot;device_orientation&quot;}, {sizeof(struct sensor_pose_6dof), &quot;pose_6dof&quot;}, {sizeof(struct sensor_gas), &quot;gas&quot;}, {sizeof(struct sensor_event), &quot;significant_motion&quot;}, {sizeof(struct sensor_hbeat), &quot;hbeat&quot;}, {sizeof(struct sensor_force), &quot;force&quot;}, {sizeof(struct sensor_hall), &quot;hall&quot;}, {sizeof(struct sensor_event), &quot;offbody_detector&quot;}, {sizeof(struct sensor_uv), &quot;uv&quot;}, {sizeof(struct sensor_angle), &quot;hinge_angle&quot;}, {sizeof(struct sensor_ir), &quot;ir&quot;}, {sizeof(struct sensor_hcho), &quot;hcho&quot;}, {sizeof(struct sensor_tvoc), &quot;tvoc&quot;}, {sizeof(struct sensor_dust), &quot;dust&quot;}, {sizeof(struct sensor_ecg), &quot;ecg&quot;}, {sizeof(struct sensor_ppgd), &quot;ppgd&quot;}, {sizeof(struct sensor_ppgq), &quot;ppgq&quot;}, {sizeof(struct sensor_impd), &quot;impd&quot;}, {sizeof(struct sensor_ots), &quot;ots&quot;}, {sizeof(struct sensor_co2), &quot;co2&quot;}, {sizeof(struct sensor_cap), &quot;cap&quot;}, {sizeof(struct sensor_eng), &quot;eng&quot;}, {sizeof(struct sensor_gnss), &quot;gnss&quot;}, {sizeof(struct sensor_gnss_satellite), &quot;gnss_satellite&quot;}, {sizeof(struct sensor_gnss_measurement), &quot;gnss_measurement&quot;}, {sizeof(struct sensor_gnss_clock), &quot;gnss_clock&quot;}, {sizeof(struct sensor_gnss_geofence_event), &quot;gnss_geofence_event&quot;}, }; static const struct file_operations g_sensor_fops = { sensor_open, /* open */ sensor_close, /* close */ sensor_read, /* read */ sensor_write, /* write */ NULL, /* seek */ sensor_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ sensor_poll /* poll */ }; /**************************************************************************** * Private Functions ****************************************************************************/ static void sensor_lock(FAR void *priv) { FAR struct sensor_upperhalf_s *upper = priv; nxrmutex_lock(&amp;upper-&gt;lock); } static void sensor_unlock(FAR void *priv) { FAR struct sensor_upperhalf_s *upper = priv; nxrmutex_unlock(&amp;upper-&gt;lock); } static int sensor_update_interval(FAR struct file *filep, FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user, uint32_t interval) { FAR struct sensor_lowerhalf_s *lower = upper-&gt;lower; FAR struct sensor_user_s *tmp; uint32_t min_interval = interval; uint32_t min_latency = interval != UINT32_MAX ? user-&gt;state.latency : UINT32_MAX; int ret = 0; if (interval == user-&gt;state.interval) { return 0; } list_for_every_entry(&amp;upper-&gt;userlist, tmp, struct sensor_user_s, node) { if (tmp == user || tmp-&gt;state.interval == UINT32_MAX) { continue; } if (min_interval &gt; tmp-&gt;state.interval) { min_interval = tmp-&gt;state.interval; } if (min_latency &gt; tmp-&gt;state.latency) { min_latency = tmp-&gt;state.latency; } } if (lower-&gt;ops-&gt;set_interval) { if (min_interval != UINT32_MAX &amp;&amp; min_interval != upper-&gt;state.min_interval) { uint32_t expected_interval = min_interval; ret = lower-&gt;ops-&gt;set_interval(lower, filep, &amp;min_interval); if (ret &lt; 0) { return ret; } else if (min_interval &gt; expected_interval) { return -EINVAL; } } if (min_latency == UINT32_MAX) { min_latency = 0; } if (lower-&gt;ops-&gt;batch &amp;&amp; (min_latency != upper-&gt;state.min_latency || (min_interval != upper-&gt;state.min_interval &amp;&amp; min_latency))) { ret = lower-&gt;ops-&gt;batch(lower, filep, &amp;min_latency); if (ret &gt;= 0) { upper-&gt;state.min_latency = min_latency; } } } upper-&gt;state.min_interval = min_interval; user-&gt;state.interval = interval; sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR); return ret; } static int sensor_update_latency(FAR struct file *filep, FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user, uint32_t latency) { FAR struct sensor_lowerhalf_s *lower = upper-&gt;lower; FAR struct sensor_user_s *tmp; uint32_t min_latency = latency; int ret = 0; if (latency == user-&gt;state.latency) { return 0; } if (user-&gt;state.interval == UINT32_MAX) { user-&gt;state.latency = latency; return 0; } if (latency &lt;= upper-&gt;state.min_latency) { goto update; } list_for_every_entry(&amp;upper-&gt;userlist, tmp, struct sensor_user_s, node) { if (tmp == user || tmp-&gt;state.interval == UINT32_MAX) { continue; } if (min_latency &gt; tmp-&gt;state.latency) { min_latency = tmp-&gt;state.latency; } } update: if (min_latency == UINT32_MAX) { min_latency = 0; } if (min_latency == upper-&gt;state.min_latency) { user-&gt;state.latency = latency; return ret; } if (lower-&gt;ops-&gt;batch) { ret = lower-&gt;ops-&gt;batch(lower, filep, &amp;min_latency); if (ret &lt; 0) { return ret; } } upper-&gt;state.min_latency = min_latency; user-&gt;state.latency = latency; sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR); return ret; } static void sensor_generate_timing(FAR struct sensor_upperhalf_s *upper, unsigned long nums) { uint32_t interval = upper-&gt;state.min_interval != UINT32_MAX ? upper-&gt;state.min_interval : 1; while (nums-- &gt; 0) { upper-&gt;state.generation += interval; circbuf_overwrite(&amp;upper-&gt;timing, &amp;upper-&gt;state.generation, TIMING_BUF_ESIZE); } } static bool sensor_is_updated(FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user) { long delta = (long long)upper-&gt;state.generation - user-&gt;state.generation; if (delta &lt;= 0) { return false; } else if (user-&gt;state.interval == UINT32_MAX) { return true; } else { /* Check whether next generation user want in buffer. * generation next generation(not published yet) * ____v_____________v * ////|//////^ | * ^ middle point * next generation user want */ return delta &gt;= user-&gt;state.interval - (upper-&gt;state.min_interval &gt;&gt; 1); } } static void sensor_catch_up(FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user) { uint32_t generation; long delta; circbuf_peek(&amp;upper-&gt;timing, &amp;generation, TIMING_BUF_ESIZE); delta = (long long)generation - user-&gt;state.generation; if (delta &gt; 0) { user-&gt;bufferpos = upper-&gt;timing.tail / TIMING_BUF_ESIZE; if (user-&gt;state.interval == UINT32_MAX) { user-&gt;state.generation = generation - 1; } else { delta -= upper-&gt;state.min_interval &gt;&gt; 1; user-&gt;state.generation += ROUND_DOWN(delta, user-&gt;state.interval); } } } static ssize_t sensor_do_samples(FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user, FAR char *buffer, size_t len) { uint32_t generation; ssize_t ret = 0; size_t nums; size_t pos; size_t end; sensor_catch_up(upper, user); nums = upper-&gt;timing.head / TIMING_BUF_ESIZE - user-&gt;bufferpos; if (len &lt; nums * upper-&gt;state.esize) { nums = len / upper-&gt;state.esize; } len = nums * upper-&gt;state.esize; /* Take samples continuously */ if (user-&gt;state.interval == UINT32_MAX) { if (buffer != NULL) { ret = circbuf_peekat(&amp;upper-&gt;buffer, user-&gt;bufferpos * upper-&gt;state.esize, buffer, len); } else { ret = len; } user-&gt;bufferpos += nums; circbuf_peekat(&amp;upper-&gt;timing, (user-&gt;bufferpos - 1) * TIMING_BUF_ESIZE, &amp;user-&gt;state.generation, TIMING_BUF_ESIZE); return ret; } /* Take samples one-bye-one, to determine whether a sample needed: * * If user&#39;s next generation is on the left side of middle point, * we should copy this sample for user. * next_generation(or end) * ________________v____ * timing buffer: //|//////. | * ^ middle * generation * next sample(or end) * ________________v____ * data buffer: | | * ^ * sample */ pos = user-&gt;bufferpos; end = upper-&gt;timing.head / TIMING_BUF_ESIZE; circbuf_peekat(&amp;upper-&gt;timing, pos * TIMING_BUF_ESIZE, &amp;generation, TIMING_BUF_ESIZE); while (pos++ != end) { uint32_t next_generation; long delta; if (pos * TIMING_BUF_ESIZE == upper-&gt;timing.head) { next_generation = upper-&gt;state.generation + upper-&gt;state.min_interval; } else { circbuf_peekat(&amp;upper-&gt;timing, pos * TIMING_BUF_ESIZE, &amp;next_generation, TIMING_BUF_ESIZE); } delta = next_generation + generation - ((user-&gt;state.generation + user-&gt;state.interval) &lt;&lt; 1); if (delta &gt;= 0) { if (buffer != NULL) { ret += circbuf_peekat(&amp;upper-&gt;buffer, (pos - 1) * upper-&gt;state.esize, buffer + ret, upper-&gt;state.esize); } else { ret += upper-&gt;state.esize; } user-&gt;bufferpos = pos; user-&gt;state.generation += user-&gt;state.interval; if (ret &gt;= len) { break; } } generation = next_generation; } if (pos - 1 == end &amp;&amp; sensor_is_updated(upper, user)) { generation = upper-&gt;state.generation - user-&gt;state.generation + (upper-&gt;state.min_interval &gt;&gt; 1); user-&gt;state.generation += ROUND_DOWN(generation, user-&gt;state.interval); } return ret; } static void sensor_pollnotify_one(FAR struct sensor_user_s *user, pollevent_t eventset, sensor_role_t role) { if (!(user-&gt;role &amp; role)) { return; } if (eventset == POLLPRI) { user-&gt;changed = true; } poll_notify(&amp;user-&gt;fds, 1, eventset); } static void sensor_pollnotify(FAR struct sensor_upperhalf_s *upper, pollevent_t eventset, sensor_role_t role) { FAR struct sensor_user_s *user; list_for_every_entry(&amp;upper-&gt;userlist, user, struct sensor_user_s, node) { sensor_pollnotify_one(user, eventset, role); } } static int sensor_open(FAR struct file *filep) { FAR struct inode *inode = filep-&gt;f_inode; FAR struct sensor_upperhalf_s *upper = inode-&gt;i_private; FAR struct sensor_lowerhalf_s *lower = upper-&gt;lower; FAR struct sensor_user_s *user; int ret = 0; nxrmutex_lock(&amp;upper-&gt;lock); user = kmm_zalloc(sizeof(struct sensor_user_s)); if (user == NULL) { ret = -ENOMEM; goto errout_with_lock; } if (lower-&gt;ops-&gt;open) { ret = lower-&gt;ops-&gt;open(lower, filep); if (ret &lt; 0) { goto errout_with_user; } } if ((filep-&gt;f_oflags &amp; O_DIRECT) == 0) { if (filep-&gt;f_oflags &amp; O_RDOK) { if (upper-&gt;state.nsubscribers == 0 &amp;&amp; lower-&gt;ops-&gt;activate) { ret = lower-&gt;ops-&gt;activate(lower, filep, true); if (ret &lt; 0) { goto errout_with_open; } } user-&gt;role |= SENSOR_ROLE_RD; upper-&gt;state.nsubscribers++; } if (filep-&gt;f_oflags &amp; O_WROK) { user-&gt;role |= SENSOR_ROLE_WR; upper-&gt;state.nadvertisers++; if (filep-&gt;f_oflags &amp; SENSOR_PERSIST) { lower-&gt;persist = true; } } } if (upper-&gt;state.generation &amp;&amp; lower-&gt;persist) { user-&gt;state.generation = upper-&gt;state.generation - 1; user-&gt;bufferpos = upper-&gt;timing.head / TIMING_BUF_ESIZE - 1; } else { user-&gt;state.generation = upper-&gt;state.generation; user-&gt;bufferpos = upper-&gt;timing.head / TIMING_BUF_ESIZE; } user-&gt;state.interval = UINT32_MAX; user-&gt;state.esize = upper-&gt;state.esize; nxsem_init(&amp;user-&gt;buffersem, 0, 0); list_add_tail(&amp;upper-&gt;userlist, &amp;user-&gt;node); /* The new user generation, notify to other users */ sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR); filep-&gt;f_priv = user; goto errout_with_lock; errout_with_open: if (lower-&gt;ops-&gt;close) { lower-&gt;ops-&gt;close(lower, filep); } errout_with_user: kmm_free(user); errout_with_lock: nxrmutex_unlock(&amp;upper-&gt;lock); return ret; } static int sensor_close(FAR struct file *filep) { FAR struct inode *inode = filep-&gt;f_inode; FAR struct sensor_upperhalf_s *upper = inode-&gt;i_private; FAR struct sensor_lowerhalf_s *lower = upper-&gt;lower; FAR struct sensor_user_s *user = filep-&gt;f_priv; int ret = 0; nxrmutex_lock(&amp;upper-&gt;lock); if (lower-&gt;ops-&gt;close) { ret = lower-&gt;ops-&gt;close(lower, filep); if (ret &lt; 0) { nxrmutex_unlock(&amp;upper-&gt;lock); return ret; } } if ((filep-&gt;f_oflags &amp; O_DIRECT) == 0) { if (filep-&gt;f_oflags &amp; O_RDOK) { upper-&gt;state.nsubscribers--; if (upper-&gt;state.nsubscribers == 0 &amp;&amp; lower-&gt;ops-&gt;activate) { lower-&gt;ops-&gt;activate(lower, filep, false); } } if (filep-&gt;f_oflags &amp; O_WROK) { upper-&gt;state.nadvertisers--; } } list_delete(&amp;user-&gt;node); sensor_update_latency(filep, upper, user, UINT32_MAX); sensor_update_interval(filep, upper, user, UINT32_MAX); nxsem_destroy(&amp;user-&gt;buffersem); /* The user is closed, notify to other users */ sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR); nxrmutex_unlock(&amp;upper-&gt;lock); kmm_free(user); return ret; } static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer, size_t len) { FAR struct inode *inode = filep-&gt;f_inode; FAR struct sensor_upperhalf_s *upper = inode-&gt;i_private; FAR struct sensor_lowerhalf_s *lower = upper-&gt;lower; FAR struct sensor_user_s *user = filep-&gt;f_priv; ssize_t ret; if (!len) { return -EINVAL; } nxrmutex_lock(&amp;upper-&gt;lock); if (lower-&gt;ops-&gt;fetch) { if (buffer == NULL) { return -EINVAL; } if (!(filep-&gt;f_oflags &amp; O_NONBLOCK)) { nxrmutex_unlock(&amp;upper-&gt;lock); ret = nxsem_wait_uninterruptible(&amp;user-&gt;buffersem); if (ret &lt; 0) { return ret; } nxrmutex_lock(&amp;upper-&gt;lock); } else if (!upper-&gt;state.nsubscribers) { ret = -EAGAIN; goto out; } ret = lower-&gt;ops-&gt;fetch(lower, filep, buffer, len); } else if (circbuf_is_empty(&amp;upper-&gt;buffer)) { ret = -ENODATA; } else if (sensor_is_updated(upper, user)) { ret = sensor_do_samples(upper, user, buffer, len); } else if (lower-&gt;persist) { if (buffer == NULL) { ret = upper-&gt;state.esize; } else { /* Persistent device can get latest old data if not updated. */ ret = circbuf_peekat(&amp;upper-&gt;buffer, (user-&gt;bufferpos - 1) * upper-&gt;state.esize, buffer, upper-&gt;state.esize); } } else { ret = -ENODATA; } out: nxrmutex_unlock(&amp;upper-&gt;lock); return ret; } static ssize_t sensor_write(FAR struct file *filep, FAR const char *buffer, size_t buflen) { FAR struct inode *inode = filep-&gt;f_inode; FAR struct sensor_upperhalf_s *upper = inode-&gt;i_private; FAR struct sensor_lowerhalf_s *lower = upper-&gt;lower; return lower-&gt;push_event(lower-&gt;priv, buffer, buflen); } static int sensor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { FAR struct inode *inode = filep-&gt;f_inode; FAR struct sensor_upperhalf_s *upper = inode-&gt;i_private; FAR struct sensor_lowerhalf_s *lower = upper-&gt;lower; FAR struct sensor_user_s *user = filep-&gt;f_priv; uint32_t arg1 = (uint32_t)arg; int ret = 0; switch (cmd) { case SNIOC_GET_STATE: { nxrmutex_lock(&amp;upper-&gt;lock); memcpy((FAR void *)(uintptr_t)arg, &amp;upper-&gt;state, sizeof(upper-&gt;state)); user-&gt;changed = false; nxrmutex_unlock(&amp;upper-&gt;lock); } break; case SNIOC_GET_USTATE: { nxrmutex_lock(&amp;upper-&gt;lock); memcpy((FAR void *)(uintptr_t)arg, &amp;user-&gt;state, sizeof(user-&gt;state)); nxrmutex_unlock(&amp;upper-&gt;lock); } break; case SNIOC_SET_INTERVAL: { nxrmutex_lock(&amp;upper-&gt;lock); ret = sensor_update_interval(filep, upper, user, arg1 ? arg1 : UINT32_MAX); nxrmutex_unlock(&amp;upper-&gt;lock); } break; case SNIOC_BATCH: { nxrmutex_lock(&amp;upper-&gt;lock); ret = sensor_update_latency(filep, upper, user, arg1); nxrmutex_unlock(&amp;upper-&gt;lock); } break; case SNIOC_SELFTEST: { if (lower-&gt;ops-&gt;selftest == NULL) { ret = -ENOTSUP; break; } ret = lower-&gt;ops-&gt;selftest(lower, filep, arg); } break; case SNIOC_SET_CALIBVALUE: { if (lower-&gt;ops-&gt;set_calibvalue == NULL) { ret = -ENOTSUP; break; } ret = lower-&gt;ops-&gt;set_calibvalue(lower, filep, arg); } break; case SNIOC_CALIBRATE: { if (lower-&gt;ops-&gt;calibrate == NULL) { ret = -ENOTSUP; break; } ret = lower-&gt;ops-&gt;calibrate(lower, filep, arg); } break; case SNIOC_SET_USERPRIV: { nxrmutex_lock(&amp;upper-&gt;lock); upper-&gt;state.priv = (uint64_t)arg; nxrmutex_unlock(&amp;upper-&gt;lock); } break; case SNIOC_SET_BUFFER_NUMBER: { nxrmutex_lock(&amp;upper-&gt;lock); if (!circbuf_is_init(&amp;upper-&gt;buffer)) { if (arg1 &gt;= lower-&gt;nbuffer) { lower-&gt;nbuffer = arg1; upper-&gt;state.nbuffer = arg1; } else { ret = -ERANGE; } } else { ret = -EBUSY; } nxrmutex_unlock(&amp;upper-&gt;lock); } break; case SNIOC_UPDATED: { nxrmutex_lock(&amp;upper-&gt;lock); *(FAR bool *)(uintptr_t)arg = sensor_is_updated(upper, user); nxrmutex_unlock(&amp;upper-&gt;lock); } break; case SNIOC_GET_INFO: { if (lower-&gt;ops-&gt;get_info == NULL) { ret = -ENOTSUP; break; } ret = lower-&gt;ops-&gt;get_info(lower, filep, (FAR struct sensor_device_info_s *)(uintptr_t)arg); } break; case SNIOC_GET_EVENTS: { nxrmutex_lock(&amp;upper-&gt;lock); *(FAR unsigned int *)(uintptr_t)arg = user-&gt;event; user-&gt;event = 0; user-&gt;changed = false; nxrmutex_unlock(&amp;upper-&gt;lock); } break; case SNIOC_FLUSH: { nxrmutex_lock(&amp;upper-&gt;lock); /* If the sensor is not activated, return -EINVAL. */ if (upper-&gt;state.nsubscribers == 0) { nxrmutex_unlock(&amp;upper-&gt;lock); return -EINVAL; } if (lower-&gt;ops-&gt;flush != NULL) { /* Lower half driver will do flush in asynchronous mode, * flush will be completed until push event happened with * bytes is zero. */ ret = lower-&gt;ops-&gt;flush(lower, filep); if (ret &gt;= 0) { user-&gt;flushing = true; } } else { /* If flush is not supported, complete immediately */ user-&gt;event |= SENSOR_EVENT_FLUSH_COMPLETE; sensor_pollnotify_one(user, POLLPRI, user-&gt;role); } nxrmutex_unlock(&amp;upper-&gt;lock); } break; default: /* Lowerhalf driver process other cmd. */ if (lower-&gt;ops-&gt;control) { ret = lower-&gt;ops-&gt;control(lower, filep, cmd, arg); } else { ret = -ENOTTY; } break; } return ret; } static int sensor_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup) { FAR struct inode *inode = filep-&gt;f_inode; FAR struct sensor_upperhalf_s *upper = inode-&gt;i_private; FAR struct sensor_lowerhalf_s *lower = upper-&gt;lower; FAR struct sensor_user_s *user = filep-&gt;f_priv; pollevent_t eventset = 0; int semcount; int ret = 0; nxrmutex_lock(&amp;upper-&gt;lock); if (setup) { /* Don&#39;t have enough space to store fds */ if (user-&gt;fds) { ret = -ENOSPC; goto errout; } user-&gt;fds = fds; fds-&gt;priv = filep; if (lower-&gt;ops-&gt;fetch) { /* Always return POLLIN for fetch data directly(non-block) */ if (filep-&gt;f_oflags &amp; O_NONBLOCK) { eventset |= POLLIN; } else { nxsem_get_value(&amp;user-&gt;buffersem, &amp;semcount); if (semcount &gt; 0) { eventset |= POLLIN; } } } else if (sensor_is_updated(upper, user)) { eventset |= POLLIN; } if (user-&gt;changed) { eventset |= POLLPRI; } poll_notify(&amp;fds, 1, eventset); } else { user-&gt;fds = NULL; fds-&gt;priv = NULL; } errout: nxrmutex_unlock(&amp;upper-&gt;lock); return ret; } static ssize_t sensor_push_event(FAR void *priv, FAR const void *data, size_t bytes) { FAR struct sensor_upperhalf_s *upper = priv; FAR struct sensor_lowerhalf_s *lower = upper-&gt;lower; FAR struct sensor_user_s *user; unsigned long envcount; int semcount; int ret; nxrmutex_lock(&amp;upper-&gt;lock); if (bytes == 0) { list_for_every_entry(&amp;upper-&gt;userlist, user, struct sensor_user_s, node) { if (user-&gt;flushing) { user-&gt;flushing = false; user-&gt;event |= SENSOR_EVENT_FLUSH_COMPLETE; sensor_pollnotify_one(user, POLLPRI, user-&gt;role); } } nxrmutex_unlock(&amp;upper-&gt;lock); return 0; } envcount = bytes / upper-&gt;state.esize; if (bytes != envcount * upper-&gt;state.esize) { nxrmutex_unlock(&amp;upper-&gt;lock); return -EINVAL; } if (!circbuf_is_init(&amp;upper-&gt;buffer)) { /* Initialize sensor buffer when data is first generated */ ret = circbuf_init(&amp;upper-&gt;buffer, NULL, lower-&gt;nbuffer * upper-&gt;state.esize); if (ret &lt; 0) { nxrmutex_unlock(&amp;upper-&gt;lock); return ret; } ret = circbuf_init(&amp;upper-&gt;timing, NULL, lower-&gt;nbuffer * TIMING_BUF_ESIZE); if (ret &lt; 0) { circbuf_uninit(&amp;upper-&gt;buffer); nxrmutex_unlock(&amp;upper-&gt;lock); return ret; } } circbuf_overwrite(&amp;upper-&gt;buffer, data, bytes); sensor_generate_timing(upper, envcount); list_for_every_entry(&amp;upper-&gt;userlist, user, struct sensor_user_s, node) { if (sensor_is_updated(upper, user)) { nxsem_get_value(&amp;user-&gt;buffersem, &amp;semcount); if (semcount &lt; 1) { nxsem_post(&amp;user-&gt;buffersem); } sensor_pollnotify_one(user, POLLIN, SENSOR_ROLE_RD); } } nxrmutex_unlock(&amp;upper-&gt;lock); return bytes; } static void sensor_notify_event(FAR void *priv) { FAR struct sensor_upperhalf_s *upper = priv; FAR struct sensor_user_s *user; int semcount; nxrmutex_lock(&amp;upper-&gt;lock); list_for_every_entry(&amp;upper-&gt;userlist, user, struct sensor_user_s, node) { nxsem_get_value(&amp;user-&gt;buffersem, &amp;semcount); if (semcount &lt; 1) { nxsem_post(&amp;user-&gt;buffersem); } sensor_pollnotify_one(user, POLLIN, SENSOR_ROLE_RD); } nxrmutex_unlock(&amp;upper-&gt;lock); } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: sensor_remap_vector_raw16 * * Description: * This function remap the sensor data according to the place position on * board. The value of place is determined base on g_remap_tbl. * * Input Parameters: * in - A pointer to input data need remap. * out - A pointer to output data. * place - The place position of sensor on board, * ex:SENSOR_BODY_COORDINATE_PX * ****************************************************************************/ void sensor_remap_vector_raw16(FAR const int16_t *in, FAR int16_t *out, int place) { FAR const struct sensor_axis_map_s *remap; int16_t tmp[3]; DEBUGASSERT(place &lt; (sizeof(g_remap_tbl) / sizeof(g_remap_tbl[0]))); remap = &amp;g_remap_tbl[place]; tmp[0] = in[remap-&gt;src_x] * remap-&gt;sign_x; tmp[1] = in[remap-&gt;src_y] * remap-&gt;sign_y; tmp[2] = in[remap-&gt;src_z] * remap-&gt;sign_z; memcpy(out, tmp, sizeof(tmp)); } /**************************************************************************** * Name: sensor_register * * Description: * This function binds an instance of a &quot;lower half&quot; Sensor driver with the * &quot;upper half&quot; Sensor device and registers that device so that can be used * by application code. * * We will register the chararter device by node name format based on the * type of sensor. Multiple types of the same type are distinguished by * numbers. eg: accel0, accel1 * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persists as long * as the driver persists. * devno - The user specifies which device of this type, from 0. If the * devno alerady exists, -EEXIST will be returned. * * Returned Value: * OK if the driver was successfully register; A negated errno value is * returned on any failure. * ****************************************************************************/ int sensor_register(FAR struct sensor_lowerhalf_s *lower, int devno) { FAR char *path; int ret; DEBUGASSERT(lower != NULL); path = lib_get_pathbuffer(); if (path == NULL) { return -ENOMEM; } snprintf(path, PATH_MAX, DEVNAME_FMT, g_sensor_meta[lower-&gt;type].name, lower-&gt;uncalibrated ? DEVNAME_UNCAL : &quot;&quot;, devno); ret = sensor_custom_register(lower, path, g_sensor_meta[lower-&gt;type].esize); lib_put_pathbuffer(path); return ret; } /**************************************************************************** * Name: sensor_custom_register * * Description: * This function binds an instance of a &quot;lower half&quot; Sensor driver with the * &quot;upper half&quot; Sensor device and registers that device so that can be used * by application code. * * You can register the character device type by specific path and esize. * This API corresponds to the sensor_custom_unregister. * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persists as long * as the driver persists. * path - The user specifies path of device. ex: /dev/uorb/xxx. * esize - The element size of intermediate circular buffer. * * Returned Value: * OK if the driver was successfully register; A negated errno value is * returned on any failure. * ****************************************************************************/ int sensor_custom_register(FAR struct sensor_lowerhalf_s *lower, FAR const char *path, size_t esize) { FAR struct sensor_upperhalf_s *upper; int ret = -EINVAL; DEBUGASSERT(lower != NULL); if (lower-&gt;type &gt;= SENSOR_TYPE_COUNT || !esize) { snerr(&quot;ERROR: type is invalid\n&quot;); return ret; } /* Allocate the upper-half data structure */ upper = kmm_zalloc(sizeof(struct sensor_upperhalf_s)); if (!upper) { snerr(&quot;ERROR: Allocation failed\n&quot;); return -ENOMEM; } /* Initialize the upper-half data structure */ list_initialize(&amp;upper-&gt;userlist); upper-&gt;state.esize = esize; upper-&gt;state.min_interval = UINT32_MAX; if (lower-&gt;ops-&gt;activate) { upper-&gt;state.nadvertisers = 1; } nxrmutex_init(&amp;upper-&gt;lock); /* Bind the lower half data structure member */ lower-&gt;priv = upper; lower-&gt;sensor_lock = sensor_lock; lower-&gt;sensor_unlock = sensor_unlock; if (!lower-&gt;ops-&gt;fetch) { if (!lower-&gt;nbuffer) { lower-&gt;nbuffer = 1; } lower-&gt;push_event = sensor_push_event; } else { lower-&gt;notify_event = sensor_notify_event; lower-&gt;nbuffer = 0; } #ifdef CONFIG_SENSORS_RPMSG lower = sensor_rpmsg_register(lower, path); if (lower == NULL) { ret = -EIO; goto rpmsg_err; } #endif upper-&gt;state.nbuffer = lower-&gt;nbuffer; upper-&gt;lower = lower; sninfo(&quot;Registering %s\n&quot;, path); ret = register_driver(path, &amp;g_sensor_fops, 0666, upper); if (ret) { goto drv_err; } return ret; drv_err: #ifdef CONFIG_SENSORS_RPMSG sensor_rpmsg_unregister(lower); rpmsg_err: #endif nxrmutex_destroy(&amp;upper-&gt;lock); kmm_free(upper); return ret; } /**************************************************************************** * Name: sensor_unregister * * Description: * This function unregister character node and release all resource about * upper half driver. * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persists as long * as the driver persists. * devno - The user specifies which device of this type, from 0. ****************************************************************************/ void sensor_unregister(FAR struct sensor_lowerhalf_s *lower, int devno) { FAR char *path; path = lib_get_pathbuffer(); if (path == NULL) { return; } snprintf(path, PATH_MAX, DEVNAME_FMT, g_sensor_meta[lower-&gt;type].name, lower-&gt;uncalibrated ? DEVNAME_UNCAL : &quot;&quot;, devno); sensor_custom_unregister(lower, path); lib_put_pathbuffer(path); } /**************************************************************************** * Name: sensor_custom_unregister * * Description: * This function unregister character node and release all resource about * upper half driver. This API corresponds to the sensor_custom_register. * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persists as long * as the driver persists. * path - The user specifies path of device, ex: /dev/uorb/xxx ****************************************************************************/ void sensor_custom_unregister(FAR struct sensor_lowerhalf_s *lower, FAR const char *path) { FAR struct sensor_upperhalf_s *upper; DEBUGASSERT(lower != NULL); DEBUGASSERT(lower-&gt;priv != NULL); upper = lower-&gt;priv; sninfo(&quot;UnRegistering %s\n&quot;, path); unregister_driver(path); #ifdef CONFIG_SENSORS_RPMSG sensor_rpmsg_unregister(lower); #endif nxrmutex_destroy(&amp;upper-&gt;lock); if (circbuf_is_init(&amp;upper-&gt;buffer)) { circbuf_uninit(&amp;upper-&gt;buffer); circbuf_uninit(&amp;upper-&gt;timing); } kmm_free(upper); }
07-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值