VisionIPC 2.0 (#19641)
	
		
	
				
					
				
			* Squashed vipc * Update release files * Remove else * add visionipc to release files * use poller in vipc receive * opencl framework instead of lib on macos * Fix camera webcam * Fix opencl on mac in ui * more webcam fixes * typo in ui sconsfile * Use cur_yuv_buf * visionbuf c++ class * Camera qcom was still using visionbuf_allocate * Turn loggerd back on * fix snapshot * No build needed * update test camerad * no more release callback * make encoder c++ * Revert "no more release callback" This reverts commit e5707b07002fee665d0483d90713154efc2d70d4. * fix exit handlers * No need to check errno * move release callback call * s/VIPCBufExtra/VisionIpcBufExtra/g * use non blocking connect * ui use non blocking connect * Lower condition variable wait time * Snapshot cleanup * bump cereal * bump cerealpull/19698/head
							parent
							
								
									206d072bb4
								
							
						
					
					
						commit
						fb496c692a
					
				
				 46 changed files with 398 additions and 2180 deletions
			
			
		@ -1 +1 @@ | 
				
			|||||||
Subproject commit 2220a4f10019d0e192f9cdad3bb388790e59f25b | 
					Subproject commit 266fb9b204cdf4edf5fb8ff4584a4b3eaa35cee2 | 
				
			||||||
@ -1,93 +0,0 @@ | 
				
			|||||||
#!/usr/bin/env python3 | 
					 | 
				
			||||||
import os | 
					 | 
				
			||||||
from cffi import FFI | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import numpy as np | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
gf_dir = os.path.dirname(os.path.abspath(__file__)) | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ffi = FFI() | 
					 | 
				
			||||||
ffi.cdef(""" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef enum VisionStreamType { | 
					 | 
				
			||||||
  VISION_STREAM_RGB_BACK, | 
					 | 
				
			||||||
  VISION_STREAM_RGB_FRONT, | 
					 | 
				
			||||||
  VISION_STREAM_YUV, | 
					 | 
				
			||||||
  VISION_STREAM_YUV_FRONT, | 
					 | 
				
			||||||
  VISION_STREAM_MAX, | 
					 | 
				
			||||||
} VisionStreamType; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct VisionUIInfo { | 
					 | 
				
			||||||
  int big_box_x, big_box_y; | 
					 | 
				
			||||||
  int big_box_width, big_box_height; | 
					 | 
				
			||||||
  int transformed_width, transformed_height; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int front_box_x, front_box_y; | 
					 | 
				
			||||||
  int front_box_width, front_box_height; | 
					 | 
				
			||||||
} VisionUIInfo; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct VisionStreamBufs { | 
					 | 
				
			||||||
  VisionStreamType type; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int width, height, stride; | 
					 | 
				
			||||||
  size_t buf_len; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  union { | 
					 | 
				
			||||||
    VisionUIInfo ui_info; | 
					 | 
				
			||||||
  } buf_info; | 
					 | 
				
			||||||
} VisionStreamBufs; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct VIPCBuf { | 
					 | 
				
			||||||
  int fd; | 
					 | 
				
			||||||
  size_t len; | 
					 | 
				
			||||||
  void* addr; | 
					 | 
				
			||||||
} VIPCBuf; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct VIPCBufExtra { | 
					 | 
				
			||||||
  // only for yuv | 
					 | 
				
			||||||
  uint32_t frame_id; | 
					 | 
				
			||||||
  uint64_t timestamp_eof; | 
					 | 
				
			||||||
} VIPCBufExtra; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct VisionStream { | 
					 | 
				
			||||||
  int ipc_fd; | 
					 | 
				
			||||||
  int last_idx; | 
					 | 
				
			||||||
  int last_type; | 
					 | 
				
			||||||
  int num_bufs; | 
					 | 
				
			||||||
  VisionStreamBufs bufs_info; | 
					 | 
				
			||||||
  VIPCBuf *bufs; | 
					 | 
				
			||||||
} VisionStream; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int visionstream_init(VisionStream *s, VisionStreamType type, bool tbuffer, VisionStreamBufs *out_bufs_info); | 
					 | 
				
			||||||
VIPCBuf* visionstream_get(VisionStream *s, VIPCBufExtra *out_extra); | 
					 | 
				
			||||||
void visionstream_destroy(VisionStream *s); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
""" | 
					 | 
				
			||||||
) | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class VisionIPCError(Exception): | 
					 | 
				
			||||||
  pass | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class VisionIPC(): | 
					 | 
				
			||||||
  def __init__(self, front=False): | 
					 | 
				
			||||||
    self.clib = ffi.dlopen(os.path.join(gf_dir, "libvisionipc.so")) | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    self.s = ffi.new("VisionStream*") | 
					 | 
				
			||||||
    self.buf_info = ffi.new("VisionStreamBufs*") | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    err = self.clib.visionstream_init(self.s, self.clib.VISION_STREAM_RGB_FRONT if front else self.clib.VISION_STREAM_RGB_BACK, True, self.buf_info) | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if err != 0: | 
					 | 
				
			||||||
      self.clib.visionstream_destroy(self.s) | 
					 | 
				
			||||||
      raise VisionIPCError | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def __del__(self): | 
					 | 
				
			||||||
    self.clib.visionstream_destroy(self.s) | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def get(self): | 
					 | 
				
			||||||
    buf = self.clib.visionstream_get(self.s, ffi.NULL) | 
					 | 
				
			||||||
    pbuf = ffi.buffer(buf.addr, buf.len) | 
					 | 
				
			||||||
    ret = np.frombuffer(pbuf, dtype=np.uint8).reshape((-1, self.buf_info.stride//3, 3)) | 
					 | 
				
			||||||
    return ret[:self.buf_info.height, :self.buf_info.width, [2, 1, 0]] | 
					 | 
				
			||||||
@ -1,438 +0,0 @@ | 
				
			|||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <stdbool.h> | 
					 | 
				
			||||||
#include <assert.h> | 
					 | 
				
			||||||
#include <string.h> | 
					 | 
				
			||||||
#include <unistd.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "common/efd.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "buffering.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void tbuffer_init(TBuffer *tb, int num_bufs, const char* name) { | 
					 | 
				
			||||||
  assert(num_bufs >= 3); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  memset(tb, 0, sizeof(TBuffer)); | 
					 | 
				
			||||||
  tb->reading = (bool*)calloc(num_bufs, sizeof(bool)); | 
					 | 
				
			||||||
  assert(tb->reading); | 
					 | 
				
			||||||
  tb->pending_idx = -1; | 
					 | 
				
			||||||
  tb->num_bufs = num_bufs; | 
					 | 
				
			||||||
  tb->name = name; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pthread_mutex_init(&tb->lock, NULL); | 
					 | 
				
			||||||
  pthread_cond_init(&tb->cv, NULL); | 
					 | 
				
			||||||
  tb->efd = efd_init(); | 
					 | 
				
			||||||
  assert(tb->efd >= 0); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void tbuffer_init2(TBuffer *tb, int num_bufs, const char* name, | 
					 | 
				
			||||||
                   void (*release_cb)(void* c, int idx), | 
					 | 
				
			||||||
                   void* cb_cookie) { | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  tbuffer_init(tb, num_bufs, name); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  tb->release_cb = release_cb; | 
					 | 
				
			||||||
  tb->cb_cookie = cb_cookie; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int tbuffer_efd(TBuffer *tb) { | 
					 | 
				
			||||||
  return tb->efd; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int tbuffer_select(TBuffer *tb) { | 
					 | 
				
			||||||
  pthread_mutex_lock(&tb->lock); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int i; | 
					 | 
				
			||||||
  for (i=0; i<tb->num_bufs; i++) { | 
					 | 
				
			||||||
    if (!tb->reading[i] && i != tb->pending_idx) { | 
					 | 
				
			||||||
      break; | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
  assert(i < tb->num_bufs); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pthread_mutex_unlock(&tb->lock); | 
					 | 
				
			||||||
  return i; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void tbuffer_dispatch(TBuffer *tb, int idx) { | 
					 | 
				
			||||||
  pthread_mutex_lock(&tb->lock); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (tb->pending_idx != -1) { | 
					 | 
				
			||||||
    //printf("tbuffer (%s) dropped!\n", tb->name ? tb->name : "?");
 | 
					 | 
				
			||||||
    if (tb->release_cb) { | 
					 | 
				
			||||||
      tb->release_cb(tb->cb_cookie, tb->pending_idx); | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
    tb->pending_idx = -1; | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  tb->pending_idx = idx; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  efd_write(tb->efd); | 
					 | 
				
			||||||
  pthread_cond_signal(&tb->cv); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pthread_mutex_unlock(&tb->lock); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int tbuffer_acquire(TBuffer *tb) { | 
					 | 
				
			||||||
  pthread_mutex_lock(&tb->lock); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (tb->stopped) { | 
					 | 
				
			||||||
    pthread_mutex_unlock(&tb->lock); | 
					 | 
				
			||||||
    return -1; | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  while (tb->pending_idx == -1) { | 
					 | 
				
			||||||
    pthread_cond_wait(&tb->cv, &tb->lock); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (tb->stopped) { | 
					 | 
				
			||||||
      pthread_mutex_unlock(&tb->lock); | 
					 | 
				
			||||||
      return -1; | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  efd_clear(tb->efd); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int ret = tb->pending_idx; | 
					 | 
				
			||||||
  assert(ret < tb->num_bufs); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  tb->reading[ret] = true; | 
					 | 
				
			||||||
  tb->pending_idx = -1; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pthread_mutex_unlock(&tb->lock); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return ret; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void tbuffer_release_locked(TBuffer *tb, int idx) { | 
					 | 
				
			||||||
  assert(idx < tb->num_bufs); | 
					 | 
				
			||||||
  if (!tb->reading[idx]) { | 
					 | 
				
			||||||
    printf("!! releasing tbuffer we aren't reading %d\n", idx); | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (tb->release_cb) { | 
					 | 
				
			||||||
    tb->release_cb(tb->cb_cookie, idx); | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  tb->reading[idx] = false; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void tbuffer_release(TBuffer *tb, int idx) { | 
					 | 
				
			||||||
  pthread_mutex_lock(&tb->lock); | 
					 | 
				
			||||||
  tbuffer_release_locked(tb, idx); | 
					 | 
				
			||||||
  pthread_mutex_unlock(&tb->lock); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void tbuffer_release_all(TBuffer *tb) { | 
					 | 
				
			||||||
  pthread_mutex_lock(&tb->lock); | 
					 | 
				
			||||||
  for (int i=0; i<tb->num_bufs; i++) { | 
					 | 
				
			||||||
    if (tb->reading[i]) { | 
					 | 
				
			||||||
      tbuffer_release_locked(tb, i); | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
  pthread_mutex_unlock(&tb->lock); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void tbuffer_stop(TBuffer *tb) { | 
					 | 
				
			||||||
  pthread_mutex_lock(&tb->lock); | 
					 | 
				
			||||||
  tb->stopped = true; | 
					 | 
				
			||||||
  efd_write(tb->efd); | 
					 | 
				
			||||||
  pthread_cond_signal(&tb->cv); | 
					 | 
				
			||||||
  pthread_mutex_unlock(&tb->lock); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void pool_init(Pool *s, int num_bufs) { | 
					 | 
				
			||||||
  assert(num_bufs > 3); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  memset(s, 0, sizeof(*s)); | 
					 | 
				
			||||||
  s->num_bufs = num_bufs; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  s->refcnt = (int*)calloc(num_bufs, sizeof(int)); | 
					 | 
				
			||||||
  s->ts = (int*)calloc(num_bufs, sizeof(int)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  s->counter = 1; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pthread_mutex_init(&s->lock, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void pool_init2(Pool *s, int num_bufs, | 
					 | 
				
			||||||
  void (*release_cb)(void* c, int idx), void* cb_cookie) { | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pool_init(s, num_bufs); | 
					 | 
				
			||||||
  s->cb_cookie = cb_cookie; | 
					 | 
				
			||||||
  s->release_cb = release_cb; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void pool_acquire(Pool *s, int idx) { | 
					 | 
				
			||||||
  pthread_mutex_lock(&s->lock); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  assert(idx >= 0 && idx < s->num_bufs); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  s->refcnt[idx]++; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pthread_mutex_unlock(&s->lock); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void pool_release_locked(Pool *s, int idx) { | 
					 | 
				
			||||||
  // printf("release %d refcnt %d\n", idx, s->refcnt[idx]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  assert(idx >= 0 && idx < s->num_bufs); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  assert(s->refcnt[idx] > 0); | 
					 | 
				
			||||||
  s->refcnt[idx]--; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // printf("release %d -> %d, %p\n", idx, s->refcnt[idx], s->release_cb);
 | 
					 | 
				
			||||||
  if (s->refcnt[idx] == 0 && s->release_cb) { | 
					 | 
				
			||||||
    // printf("call %p\b", s->release_cb);
 | 
					 | 
				
			||||||
    s->release_cb(s->cb_cookie, idx); | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void pool_release(Pool *s, int idx) { | 
					 | 
				
			||||||
  pthread_mutex_lock(&s->lock); | 
					 | 
				
			||||||
  pool_release_locked(s, idx); | 
					 | 
				
			||||||
  pthread_mutex_unlock(&s->lock); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TBuffer* pool_get_tbuffer(Pool *s) { | 
					 | 
				
			||||||
  pthread_mutex_lock(&s->lock); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  assert(s->num_tbufs < POOL_MAX_TBUFS); | 
					 | 
				
			||||||
  TBuffer* tbuf = &s->tbufs[s->num_tbufs]; | 
					 | 
				
			||||||
  s->num_tbufs++; | 
					 | 
				
			||||||
  tbuffer_init2(tbuf, s->num_bufs, | 
					 | 
				
			||||||
                "pool", (void (*)(void *, int))pool_release, s); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  bool stopped = s->stopped; | 
					 | 
				
			||||||
  pthread_mutex_unlock(&s->lock); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Stop the tbuffer so we can return a valid object.
 | 
					 | 
				
			||||||
  // We must stop here because the pool_stop may have already been called,
 | 
					 | 
				
			||||||
  // in which case tbuffer_stop may never be called again.
 | 
					 | 
				
			||||||
  if (stopped) { | 
					 | 
				
			||||||
    tbuffer_stop(tbuf); | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
  return tbuf; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
PoolQueue* pool_get_queue(Pool *s) { | 
					 | 
				
			||||||
  pthread_mutex_lock(&s->lock); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int i; | 
					 | 
				
			||||||
  for (i = 0; i < POOL_MAX_QUEUES; i++) { | 
					 | 
				
			||||||
    if (!s->queues[i].inited) { | 
					 | 
				
			||||||
      break; | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
  assert(i < POOL_MAX_QUEUES); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  PoolQueue *c = &s->queues[i]; | 
					 | 
				
			||||||
  memset(c, 0, sizeof(*c)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  c->pool = s; | 
					 | 
				
			||||||
  c->inited = true; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  c->efd = efd_init(); | 
					 | 
				
			||||||
  assert(c->efd >= 0); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  c->num_bufs = s->num_bufs; | 
					 | 
				
			||||||
  c->num = c->num_bufs+1; | 
					 | 
				
			||||||
  c->idx = (int*)malloc(sizeof(int)*c->num); | 
					 | 
				
			||||||
  memset(c->idx, -1, sizeof(int)*c->num); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pthread_mutex_init(&c->lock, NULL); | 
					 | 
				
			||||||
  pthread_cond_init(&c->cv, NULL); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pthread_mutex_unlock(&s->lock); | 
					 | 
				
			||||||
  return c; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void pool_release_queue(PoolQueue *c) { | 
					 | 
				
			||||||
  Pool *s = c->pool; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pthread_mutex_lock(&s->lock); | 
					 | 
				
			||||||
  pthread_mutex_lock(&c->lock); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (int i=0; i<c->num; i++) { | 
					 | 
				
			||||||
    if (c->idx[i] != -1) { | 
					 | 
				
			||||||
      pool_release_locked(s, c->idx[i]); | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  close(c->efd); | 
					 | 
				
			||||||
  free(c->idx); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  c->inited = false; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pthread_mutex_unlock(&c->lock); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pthread_mutex_destroy(&c->lock); | 
					 | 
				
			||||||
  pthread_cond_destroy(&c->cv); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pthread_mutex_unlock(&s->lock); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int pool_select(Pool *s) { | 
					 | 
				
			||||||
  pthread_mutex_lock(&s->lock); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int i; | 
					 | 
				
			||||||
  for (i=0; i<s->num_bufs; i++) { | 
					 | 
				
			||||||
    if (s->refcnt[i] == 0) { | 
					 | 
				
			||||||
      break; | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (i >= s->num_bufs) { | 
					 | 
				
			||||||
    // overwrite the oldest
 | 
					 | 
				
			||||||
    // still being using in a queue or tbuffer :/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int min_k = 0; | 
					 | 
				
			||||||
    int min_ts = s->ts[0]; | 
					 | 
				
			||||||
    for (int k=1; k<s->num_bufs; k++) { | 
					 | 
				
			||||||
      if (s->ts[k] < min_ts) { | 
					 | 
				
			||||||
        min_ts = s->ts[k]; | 
					 | 
				
			||||||
        min_k = k; | 
					 | 
				
			||||||
      } | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
    i = min_k; | 
					 | 
				
			||||||
    printf("pool is full! evicted %d\n", min_k); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // might be really bad if the user is doing pointery stuff
 | 
					 | 
				
			||||||
    if (s->release_cb) { | 
					 | 
				
			||||||
      s->release_cb(s->cb_cookie, min_k); | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  s->refcnt[i]++; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  s->ts[i] = s->counter; | 
					 | 
				
			||||||
  s->counter++; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pthread_mutex_unlock(&s->lock); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return i; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void pool_push(Pool *s, int idx) { | 
					 | 
				
			||||||
  pthread_mutex_lock(&s->lock); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // printf("push %d head %d tail %d\n", idx, s->head, s->tail);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  assert(idx >= 0 && idx < s->num_bufs); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  s->ts[idx] = s->counter; | 
					 | 
				
			||||||
  s->counter++; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  assert(s->refcnt[idx] > 0); | 
					 | 
				
			||||||
  s->refcnt[idx]--; //push is a implcit release
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int num_tbufs = s->num_tbufs; | 
					 | 
				
			||||||
  s->refcnt[idx] += num_tbufs; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // dispatch pool queues
 | 
					 | 
				
			||||||
  for (int i=0; i<POOL_MAX_QUEUES; i++) { | 
					 | 
				
			||||||
    PoolQueue *c = &s->queues[i]; | 
					 | 
				
			||||||
    if (!c->inited) continue; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pthread_mutex_lock(&c->lock); | 
					 | 
				
			||||||
    if (((c->head+1) % c->num) == c->tail) { | 
					 | 
				
			||||||
      // queue is full. skip for now
 | 
					 | 
				
			||||||
      pthread_mutex_unlock(&c->lock); | 
					 | 
				
			||||||
      continue; | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    s->refcnt[idx]++; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    c->idx[c->head] = idx; | 
					 | 
				
			||||||
    c->head = (c->head+1) % c->num; | 
					 | 
				
			||||||
    assert(c->head != c->tail); | 
					 | 
				
			||||||
    pthread_mutex_unlock(&c->lock); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    efd_write(c->efd); | 
					 | 
				
			||||||
    pthread_cond_signal(&c->cv); | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pthread_mutex_unlock(&s->lock); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (int i=0; i<num_tbufs; i++) { | 
					 | 
				
			||||||
    tbuffer_dispatch(&s->tbufs[i], idx); | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int poolq_pop(PoolQueue *c) { | 
					 | 
				
			||||||
  pthread_mutex_lock(&c->lock); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (c->stopped) { | 
					 | 
				
			||||||
    pthread_mutex_unlock(&c->lock); | 
					 | 
				
			||||||
    return -1; | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  while (c->head == c->tail) { | 
					 | 
				
			||||||
    pthread_cond_wait(&c->cv, &c->lock); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (c->stopped) { | 
					 | 
				
			||||||
      pthread_mutex_unlock(&c->lock); | 
					 | 
				
			||||||
      return -1; | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // printf("pop head %d tail %d\n", s->head, s->tail);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  assert(c->head != c->tail); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int r = c->idx[c->tail]; | 
					 | 
				
			||||||
  c->idx[c->tail] = -1; | 
					 | 
				
			||||||
  c->tail = (c->tail+1) % c->num; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // queue event is level triggered
 | 
					 | 
				
			||||||
  if (c->head == c->tail) { | 
					 | 
				
			||||||
    efd_clear(c->efd); | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // printf("pop %d head %d tail %d\n", r, s->head, s->tail);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  assert(r >= 0 && r < c->num_bufs); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pthread_mutex_unlock(&c->lock); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return r; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int poolq_efd(PoolQueue *c) { | 
					 | 
				
			||||||
  return c->efd; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void poolq_release(PoolQueue *c, int idx) { | 
					 | 
				
			||||||
  pool_release(c->pool, idx); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void pool_stop(Pool *s) { | 
					 | 
				
			||||||
  for (int i=0; i<s->num_tbufs; i++) { | 
					 | 
				
			||||||
    tbuffer_stop(&s->tbufs[i]); | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pthread_mutex_lock(&s->lock); | 
					 | 
				
			||||||
  s->stopped = true; | 
					 | 
				
			||||||
  for (int i=0; i<POOL_MAX_QUEUES; i++) { | 
					 | 
				
			||||||
    PoolQueue *c = &s->queues[i]; | 
					 | 
				
			||||||
    if (!c->inited) continue; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pthread_mutex_lock(&c->lock); | 
					 | 
				
			||||||
    c->stopped = true; | 
					 | 
				
			||||||
    pthread_mutex_unlock(&c->lock); | 
					 | 
				
			||||||
    efd_write(c->efd); | 
					 | 
				
			||||||
    pthread_cond_signal(&c->cv); | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
  pthread_mutex_unlock(&s->lock); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,123 +0,0 @@ | 
				
			|||||||
#ifndef BUFFERING_H | 
					 | 
				
			||||||
#define BUFFERING_H | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdbool.h> | 
					 | 
				
			||||||
#include <pthread.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __cplusplus | 
					 | 
				
			||||||
extern "C" { | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Tripple buffering helper
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct TBuffer { | 
					 | 
				
			||||||
    pthread_mutex_t lock; | 
					 | 
				
			||||||
    pthread_cond_t cv; | 
					 | 
				
			||||||
    int efd; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool* reading; | 
					 | 
				
			||||||
    int pending_idx; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int num_bufs; | 
					 | 
				
			||||||
    const char* name; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void (*release_cb)(void* c, int idx); | 
					 | 
				
			||||||
    void *cb_cookie; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool stopped; | 
					 | 
				
			||||||
} TBuffer; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// num_bufs must be at least the number of buffers that can be acquired simultaniously plus two
 | 
					 | 
				
			||||||
void tbuffer_init(TBuffer *tb, int num_bufs, const char* name); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void tbuffer_init2(TBuffer *tb, int num_bufs, const char* name, | 
					 | 
				
			||||||
  void (*release_cb)(void* c, int idx), | 
					 | 
				
			||||||
  void* cb_cookie); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// returns an eventfd that signals if a buffer is ready and tbuffer_acquire shouldn't to block.
 | 
					 | 
				
			||||||
// useful to polling on multiple tbuffers.
 | 
					 | 
				
			||||||
int tbuffer_efd(TBuffer *tb); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Chooses a buffer that's not reading or pending
 | 
					 | 
				
			||||||
int tbuffer_select(TBuffer *tb); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Called when the writer is done with their buffer
 | 
					 | 
				
			||||||
//  - Wakes up the reader if it's waiting
 | 
					 | 
				
			||||||
//  - releases the pending buffer if the reader's too slow
 | 
					 | 
				
			||||||
void tbuffer_dispatch(TBuffer *tb, int idx); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Called when the reader wants a new buffer, will return -1 when stopped
 | 
					 | 
				
			||||||
int tbuffer_acquire(TBuffer *tb); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Called when the reader is done with their buffer
 | 
					 | 
				
			||||||
void tbuffer_release(TBuffer *tb, int idx); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void tbuffer_release_all(TBuffer *tb); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void tbuffer_stop(TBuffer *tb); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// pool: buffer pool + queue thing...
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define POOL_MAX_TBUFS 8 | 
					 | 
				
			||||||
#define POOL_MAX_QUEUES 8 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct Pool Pool; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct PoolQueue { | 
					 | 
				
			||||||
  pthread_mutex_t lock; | 
					 | 
				
			||||||
  pthread_cond_t cv; | 
					 | 
				
			||||||
  Pool* pool; | 
					 | 
				
			||||||
  bool inited; | 
					 | 
				
			||||||
  bool stopped; | 
					 | 
				
			||||||
  int efd; | 
					 | 
				
			||||||
  int num_bufs; | 
					 | 
				
			||||||
  int num; | 
					 | 
				
			||||||
  int head, tail; | 
					 | 
				
			||||||
  int* idx; | 
					 | 
				
			||||||
} PoolQueue; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int poolq_pop(PoolQueue *s); | 
					 | 
				
			||||||
int poolq_efd(PoolQueue *s); | 
					 | 
				
			||||||
void poolq_release(PoolQueue *c, int idx); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct Pool { | 
					 | 
				
			||||||
  pthread_mutex_t lock; | 
					 | 
				
			||||||
  bool stopped; | 
					 | 
				
			||||||
  int num_bufs; | 
					 | 
				
			||||||
  int counter; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int* ts; | 
					 | 
				
			||||||
  int* refcnt; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void (*release_cb)(void* c, int idx); | 
					 | 
				
			||||||
  void *cb_cookie; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int num_tbufs; | 
					 | 
				
			||||||
  TBuffer tbufs[POOL_MAX_TBUFS]; | 
					 | 
				
			||||||
  PoolQueue queues[POOL_MAX_QUEUES]; | 
					 | 
				
			||||||
} Pool; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void pool_init(Pool *s, int num_bufs); | 
					 | 
				
			||||||
void pool_init2(Pool *s, int num_bufs, | 
					 | 
				
			||||||
  void (*release_cb)(void* c, int idx), void* cb_cookie); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TBuffer* pool_get_tbuffer(Pool *s); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
PoolQueue* pool_get_queue(Pool *s); | 
					 | 
				
			||||||
void pool_release_queue(PoolQueue *q); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int pool_select(Pool *s); | 
					 | 
				
			||||||
void pool_push(Pool *s, int idx); | 
					 | 
				
			||||||
void pool_acquire(Pool *s, int idx); | 
					 | 
				
			||||||
void pool_release(Pool *s, int idx); | 
					 | 
				
			||||||
void pool_stop(Pool *s); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __cplusplus | 
					 | 
				
			||||||
}  // extern "C"
 | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
@ -1,56 +0,0 @@ | 
				
			|||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <assert.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __linux__ | 
					 | 
				
			||||||
#include <sys/eventfd.h> | 
					 | 
				
			||||||
#else | 
					 | 
				
			||||||
#include <sys/time.h> | 
					 | 
				
			||||||
#include <sys/event.h> | 
					 | 
				
			||||||
#define EVENT_IDENT 42 | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "efd.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int efd_init() { | 
					 | 
				
			||||||
#ifdef __linux__ | 
					 | 
				
			||||||
  return eventfd(0, EFD_CLOEXEC); | 
					 | 
				
			||||||
#else | 
					 | 
				
			||||||
  int fd = kqueue(); | 
					 | 
				
			||||||
  assert(fd >= 0); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  struct kevent kev; | 
					 | 
				
			||||||
  EV_SET(&kev, EVENT_IDENT, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, NULL); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  struct timespec timeout = {0, 0}; | 
					 | 
				
			||||||
  int err = kevent(fd, &kev, 1, NULL, 0, &timeout); | 
					 | 
				
			||||||
  assert(err != -1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return fd; | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void efd_write(int fd) { | 
					 | 
				
			||||||
#ifdef __linux__ | 
					 | 
				
			||||||
  eventfd_write(fd, 1); | 
					 | 
				
			||||||
#else | 
					 | 
				
			||||||
  struct kevent kev; | 
					 | 
				
			||||||
  EV_SET(&kev, EVENT_IDENT, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  struct timespec timeout = {0, 0}; | 
					 | 
				
			||||||
  int err = kevent(fd, &kev, 1, NULL, 0, &timeout); | 
					 | 
				
			||||||
  assert(err != -1); | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void efd_clear(int fd) { | 
					 | 
				
			||||||
#ifdef __linux__ | 
					 | 
				
			||||||
  eventfd_t efd_cnt; | 
					 | 
				
			||||||
  eventfd_read(fd, &efd_cnt); | 
					 | 
				
			||||||
#else | 
					 | 
				
			||||||
  struct kevent kev; | 
					 | 
				
			||||||
  struct timespec timeout = {0, 0}; | 
					 | 
				
			||||||
  int nfds = kevent(fd, NULL, 0, &kev, 1, &timeout); | 
					 | 
				
			||||||
  assert(nfds != -1); | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,17 +0,0 @@ | 
				
			|||||||
#ifndef EFD_H | 
					 | 
				
			||||||
#define EFD_H | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __cplusplus | 
					 | 
				
			||||||
extern "C" { | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// event fd: a semaphore that can be poll()'d
 | 
					 | 
				
			||||||
int efd_init(); | 
					 | 
				
			||||||
void efd_write(int fd); | 
					 | 
				
			||||||
void efd_clear(int fd); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __cplusplus | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
@ -1,125 +0,0 @@ | 
				
			|||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <stdbool.h> | 
					 | 
				
			||||||
#include <string.h> | 
					 | 
				
			||||||
#include <unistd.h> | 
					 | 
				
			||||||
#include <assert.h> | 
					 | 
				
			||||||
#include <errno.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <sys/mman.h> | 
					 | 
				
			||||||
#include <sys/socket.h> | 
					 | 
				
			||||||
#include <sys/un.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ipc.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int ipc_connect(const char* socket_path) { | 
					 | 
				
			||||||
  int err; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __APPLE__ | 
					 | 
				
			||||||
  int sock = socket(AF_UNIX, SOCK_STREAM, 0); | 
					 | 
				
			||||||
#else | 
					 | 
				
			||||||
  int sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
  if (sock < 0) return -1; | 
					 | 
				
			||||||
  struct sockaddr_un addr = { | 
					 | 
				
			||||||
    .sun_family = AF_UNIX, | 
					 | 
				
			||||||
  }; | 
					 | 
				
			||||||
  snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socket_path); | 
					 | 
				
			||||||
  err = connect(sock, (struct sockaddr*)&addr, sizeof(addr)); | 
					 | 
				
			||||||
  if (err != 0) { | 
					 | 
				
			||||||
    close(sock); | 
					 | 
				
			||||||
    return -1; | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return sock; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int ipc_bind(const char* socket_path) { | 
					 | 
				
			||||||
  int err; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  unlink(socket_path); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __APPLE__ | 
					 | 
				
			||||||
  int sock = socket(AF_UNIX, SOCK_STREAM, 0); | 
					 | 
				
			||||||
#else | 
					 | 
				
			||||||
  int sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
  struct sockaddr_un addr = { | 
					 | 
				
			||||||
    .sun_family = AF_UNIX, | 
					 | 
				
			||||||
  }; | 
					 | 
				
			||||||
  snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socket_path); | 
					 | 
				
			||||||
  err = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); | 
					 | 
				
			||||||
  assert(err == 0); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  err = listen(sock, 3); | 
					 | 
				
			||||||
  assert(err == 0); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return sock; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int ipc_sendrecv_with_fds(bool send, int fd, void *buf, size_t buf_size, int* fds, int num_fds, | 
					 | 
				
			||||||
                          int *out_num_fds) { | 
					 | 
				
			||||||
  char control_buf[CMSG_SPACE(sizeof(int) * num_fds)]; | 
					 | 
				
			||||||
  memset(control_buf, 0, CMSG_SPACE(sizeof(int) * num_fds)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  struct iovec iov = { | 
					 | 
				
			||||||
    .iov_base = buf, | 
					 | 
				
			||||||
    .iov_len = buf_size, | 
					 | 
				
			||||||
  }; | 
					 | 
				
			||||||
  struct msghdr msg = { | 
					 | 
				
			||||||
    .msg_iov = &iov, | 
					 | 
				
			||||||
    .msg_iovlen = 1, | 
					 | 
				
			||||||
  }; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (num_fds > 0) { | 
					 | 
				
			||||||
    assert(fds); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    msg.msg_control = control_buf; | 
					 | 
				
			||||||
    msg.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds); | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (send) { | 
					 | 
				
			||||||
    if (num_fds) { | 
					 | 
				
			||||||
      struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); | 
					 | 
				
			||||||
      assert(cmsg); | 
					 | 
				
			||||||
      cmsg->cmsg_level = SOL_SOCKET; | 
					 | 
				
			||||||
      cmsg->cmsg_type = SCM_RIGHTS; | 
					 | 
				
			||||||
      cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds); | 
					 | 
				
			||||||
      memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * num_fds); | 
					 | 
				
			||||||
      // printf("send clen %d -> %d\n", num_fds, cmsg->cmsg_len);
 | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
    return sendmsg(fd, &msg, 0); | 
					 | 
				
			||||||
  } else { | 
					 | 
				
			||||||
    int r = recvmsg(fd, &msg, 0); | 
					 | 
				
			||||||
    if (r < 0) return r; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int recv_fds = 0; | 
					 | 
				
			||||||
    if (msg.msg_controllen > 0) { | 
					 | 
				
			||||||
      struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); | 
					 | 
				
			||||||
      assert(cmsg); | 
					 | 
				
			||||||
      assert(cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS); | 
					 | 
				
			||||||
      recv_fds = (cmsg->cmsg_len - CMSG_LEN(0)); | 
					 | 
				
			||||||
      assert(recv_fds > 0 && (recv_fds % sizeof(int)) == 0); | 
					 | 
				
			||||||
      recv_fds /= sizeof(int); | 
					 | 
				
			||||||
      // printf("recv clen %d -> %d\n", cmsg->cmsg_len, recv_fds);
 | 
					 | 
				
			||||||
      // assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int) * num_fds));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      assert(fds && recv_fds <= num_fds); | 
					 | 
				
			||||||
      memcpy(fds, CMSG_DATA(cmsg), sizeof(int) * recv_fds); | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (msg.msg_flags) { | 
					 | 
				
			||||||
      for (int i=0; i<recv_fds; i++) { | 
					 | 
				
			||||||
        close(fds[i]); | 
					 | 
				
			||||||
      } | 
					 | 
				
			||||||
      return -1; | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (fds) { | 
					 | 
				
			||||||
      assert(out_num_fds); | 
					 | 
				
			||||||
      *out_num_fds = recv_fds; | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
    return r; | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,19 +0,0 @@ | 
				
			|||||||
#ifndef IPC_H | 
					 | 
				
			||||||
#define IPC_H | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdbool.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __cplusplus | 
					 | 
				
			||||||
extern "C" { | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int ipc_connect(const char* socket_path); | 
					 | 
				
			||||||
int ipc_bind(const char* socket_path); | 
					 | 
				
			||||||
int ipc_sendrecv_with_fds(bool send, int fd, void *buf, size_t buf_size, int* fds, int num_fds, | 
					 | 
				
			||||||
                          int *out_num_fds); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __cplusplus | 
					 | 
				
			||||||
}  // extern "C"
 | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
@ -1,37 +0,0 @@ | 
				
			|||||||
#pragma once | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define CL_USE_DEPRECATED_OPENCL_1_2_APIS | 
					 | 
				
			||||||
#ifdef __APPLE__ | 
					 | 
				
			||||||
#include <OpenCL/cl.h> | 
					 | 
				
			||||||
#else | 
					 | 
				
			||||||
#include <CL/cl.h> | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __cplusplus | 
					 | 
				
			||||||
extern "C" { | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct VisionBuf { | 
					 | 
				
			||||||
  size_t len; | 
					 | 
				
			||||||
  size_t mmap_len; | 
					 | 
				
			||||||
  void* addr; | 
					 | 
				
			||||||
  int handle; | 
					 | 
				
			||||||
  int fd; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  cl_context ctx; | 
					 | 
				
			||||||
  cl_device_id device_id; | 
					 | 
				
			||||||
  cl_mem buf_cl; | 
					 | 
				
			||||||
  cl_command_queue copy_q; | 
					 | 
				
			||||||
} VisionBuf; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define VISIONBUF_SYNC_FROM_DEVICE 0 | 
					 | 
				
			||||||
#define VISIONBUF_SYNC_TO_DEVICE 1 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
VisionBuf visionbuf_allocate(size_t len); | 
					 | 
				
			||||||
VisionBuf visionbuf_allocate_cl(size_t len, cl_device_id device_id, cl_context ctx); | 
					 | 
				
			||||||
void visionbuf_sync(const VisionBuf* buf, int dir); | 
					 | 
				
			||||||
void visionbuf_free(const VisionBuf* buf); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __cplusplus | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
@ -1,101 +0,0 @@ | 
				
			|||||||
#include "visionbuf.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <fcntl.h> | 
					 | 
				
			||||||
#include <assert.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <unistd.h> | 
					 | 
				
			||||||
#include <sys/mman.h> | 
					 | 
				
			||||||
#include <sys/types.h> | 
					 | 
				
			||||||
#include "common/clutil.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define CL_USE_DEPRECATED_OPENCL_1_2_APIS | 
					 | 
				
			||||||
#ifdef __APPLE__ | 
					 | 
				
			||||||
#include <OpenCL/cl.h> | 
					 | 
				
			||||||
#else | 
					 | 
				
			||||||
#include <CL/cl.h> | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int offset = 0; | 
					 | 
				
			||||||
void *malloc_with_fd(size_t len, int *fd) { | 
					 | 
				
			||||||
  char full_path[0x100]; | 
					 | 
				
			||||||
#ifdef __APPLE__ | 
					 | 
				
			||||||
  snprintf(full_path, sizeof(full_path)-1, "/tmp/visionbuf_%d_%d", getpid(), offset++); | 
					 | 
				
			||||||
#else | 
					 | 
				
			||||||
  snprintf(full_path, sizeof(full_path)-1, "/dev/shm/visionbuf_%d_%d", getpid(), offset++); | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
  *fd = open(full_path, O_RDWR | O_CREAT, 0777); | 
					 | 
				
			||||||
  assert(*fd >= 0); | 
					 | 
				
			||||||
  unlink(full_path); | 
					 | 
				
			||||||
  ftruncate(*fd, len); | 
					 | 
				
			||||||
  void *addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0); | 
					 | 
				
			||||||
  assert(addr != MAP_FAILED); | 
					 | 
				
			||||||
  return addr; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
VisionBuf visionbuf_allocate(size_t len) { | 
					 | 
				
			||||||
  // const size_t alignment = 4096;
 | 
					 | 
				
			||||||
  // void* addr = aligned_alloc(alignment, alignment * ((len - 1) / alignment + 1));
 | 
					 | 
				
			||||||
  //void* addr = calloc(1, len);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int fd; | 
					 | 
				
			||||||
  void *addr = malloc_with_fd(len, &fd); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (VisionBuf){ | 
					 | 
				
			||||||
      .len = len, .addr = addr, .handle = 1, .fd = fd, | 
					 | 
				
			||||||
  }; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
VisionBuf visionbuf_allocate_cl(size_t len, cl_device_id device_id, cl_context ctx) { | 
					 | 
				
			||||||
#if __OPENCL_VERSION__ >= 200 | 
					 | 
				
			||||||
  void* host_ptr = | 
					 | 
				
			||||||
      clSVMAlloc(ctx, CL_MEM_READ_WRITE | CL_MEM_SVM_FINE_GRAIN_BUFFER, len, 0); | 
					 | 
				
			||||||
  assert(host_ptr); | 
					 | 
				
			||||||
#else | 
					 | 
				
			||||||
  int fd; | 
					 | 
				
			||||||
  void* host_ptr = malloc_with_fd(len, &fd); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  cl_command_queue q = CL_CHECK_ERR(clCreateCommandQueue(ctx, device_id, 0, &err)); | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  cl_mem mem = CL_CHECK_ERR(clCreateBuffer(ctx, CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, len, host_ptr, &err)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (VisionBuf){ | 
					 | 
				
			||||||
      .len = len, .addr = host_ptr, .handle = 0, .fd = fd, | 
					 | 
				
			||||||
      .device_id = device_id, .ctx = ctx, .buf_cl = mem, | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if __OPENCL_VERSION__ < 200 | 
					 | 
				
			||||||
      .copy_q = q, | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  }; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void visionbuf_sync(const VisionBuf* buf, int dir) { | 
					 | 
				
			||||||
  if (!buf->buf_cl) return; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if __OPENCL_VERSION__ < 200 | 
					 | 
				
			||||||
  if (dir == VISIONBUF_SYNC_FROM_DEVICE) { | 
					 | 
				
			||||||
    CL_CHECK(clEnqueueReadBuffer(buf->copy_q, buf->buf_cl, CL_FALSE, 0, buf->len, buf->addr, 0, NULL, NULL)); | 
					 | 
				
			||||||
  } else { | 
					 | 
				
			||||||
    CL_CHECK(clEnqueueWriteBuffer(buf->copy_q, buf->buf_cl, CL_FALSE, 0, buf->len, buf->addr, 0, NULL, NULL)); | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
  clFinish(buf->copy_q); | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void visionbuf_free(const VisionBuf* buf) { | 
					 | 
				
			||||||
  if (buf->handle) { | 
					 | 
				
			||||||
    munmap(buf->addr, buf->len); | 
					 | 
				
			||||||
    close(buf->fd); | 
					 | 
				
			||||||
  } else { | 
					 | 
				
			||||||
    CL_CHECK(clReleaseMemObject(buf->buf_cl)); | 
					 | 
				
			||||||
#if __OPENCL_VERSION__ >= 200 | 
					 | 
				
			||||||
    clSVMFree(buf->ctx, buf->addr); | 
					 | 
				
			||||||
#else | 
					 | 
				
			||||||
    CL_CHECK(clReleaseCommandQueue(buf->copy_q)); | 
					 | 
				
			||||||
    munmap(buf->addr, buf->len); | 
					 | 
				
			||||||
    close(buf->fd); | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,144 +0,0 @@ | 
				
			|||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <string.h> | 
					 | 
				
			||||||
#include <assert.h> | 
					 | 
				
			||||||
#include <sys/mman.h> | 
					 | 
				
			||||||
#include <sys/ioctl.h> | 
					 | 
				
			||||||
#include <sys/types.h> | 
					 | 
				
			||||||
#include <sys/stat.h> | 
					 | 
				
			||||||
#include <fcntl.h> | 
					 | 
				
			||||||
#include <unistd.h> | 
					 | 
				
			||||||
#include <linux/ion.h> | 
					 | 
				
			||||||
#include <CL/cl_ext.h> | 
					 | 
				
			||||||
#include "common/clutil.h" | 
					 | 
				
			||||||
#include <msm_ion.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "visionbuf.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// just hard-code these for convenience
 | 
					 | 
				
			||||||
// size_t device_page_size = 0;
 | 
					 | 
				
			||||||
// clGetDeviceInfo(device_id, CL_DEVICE_PAGE_SIZE_QCOM,
 | 
					 | 
				
			||||||
//                 sizeof(device_page_size), &device_page_size,
 | 
					 | 
				
			||||||
//                 NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// size_t padding_cl = 0;
 | 
					 | 
				
			||||||
// clGetDeviceInfo(device_id, CL_DEVICE_EXT_MEM_PADDING_IN_BYTES_QCOM,
 | 
					 | 
				
			||||||
//                 sizeof(padding_cl), &padding_cl,
 | 
					 | 
				
			||||||
//                 NULL);
 | 
					 | 
				
			||||||
#define DEVICE_PAGE_SIZE_CL 4096 | 
					 | 
				
			||||||
#define PADDING_CL 0 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int ion_fd = -1; | 
					 | 
				
			||||||
static void ion_init() { | 
					 | 
				
			||||||
  if (ion_fd == -1) { | 
					 | 
				
			||||||
    ion_fd = open("/dev/ion", O_RDWR | O_NONBLOCK); | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
VisionBuf visionbuf_allocate(size_t len) { | 
					 | 
				
			||||||
  int err; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ion_init(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  struct ion_allocation_data ion_alloc = {0}; | 
					 | 
				
			||||||
  ion_alloc.len = len + PADDING_CL; | 
					 | 
				
			||||||
  ion_alloc.align = 4096; | 
					 | 
				
			||||||
  ion_alloc.heap_id_mask = 1 << ION_IOMMU_HEAP_ID; | 
					 | 
				
			||||||
  ion_alloc.flags = ION_FLAG_CACHED; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  err = ioctl(ion_fd, ION_IOC_ALLOC, &ion_alloc); | 
					 | 
				
			||||||
  assert(err == 0); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  struct ion_fd_data ion_fd_data = {0}; | 
					 | 
				
			||||||
  ion_fd_data.handle = ion_alloc.handle; | 
					 | 
				
			||||||
  err = ioctl(ion_fd, ION_IOC_SHARE, &ion_fd_data); | 
					 | 
				
			||||||
  assert(err == 0); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void *addr = mmap(NULL, ion_alloc.len, | 
					 | 
				
			||||||
                    PROT_READ | PROT_WRITE, | 
					 | 
				
			||||||
                    MAP_SHARED, ion_fd_data.fd, 0); | 
					 | 
				
			||||||
  assert(addr != MAP_FAILED); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  memset(addr, 0, ion_alloc.len); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (VisionBuf){ | 
					 | 
				
			||||||
    .len = len, | 
					 | 
				
			||||||
    .mmap_len = ion_alloc.len, | 
					 | 
				
			||||||
    .addr = addr, | 
					 | 
				
			||||||
    .handle = ion_alloc.handle, | 
					 | 
				
			||||||
    .fd = ion_fd_data.fd, | 
					 | 
				
			||||||
  }; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
VisionBuf visionbuf_allocate_cl(size_t len, cl_device_id device_id, cl_context ctx) { | 
					 | 
				
			||||||
  VisionBuf buf = visionbuf_allocate(len); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  assert(((uintptr_t)buf.addr % DEVICE_PAGE_SIZE_CL) == 0); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  cl_mem_ion_host_ptr ion_cl = {0}; | 
					 | 
				
			||||||
  ion_cl.ext_host_ptr.allocation_type = CL_MEM_ION_HOST_PTR_QCOM; | 
					 | 
				
			||||||
  ion_cl.ext_host_ptr.host_cache_policy = CL_MEM_HOST_UNCACHED_QCOM; | 
					 | 
				
			||||||
  ion_cl.ion_filedesc = buf.fd; | 
					 | 
				
			||||||
  ion_cl.ion_hostptr = buf.addr; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  buf.buf_cl = CL_CHECK_ERR(clCreateBuffer(ctx, | 
					 | 
				
			||||||
                              CL_MEM_USE_HOST_PTR | CL_MEM_EXT_HOST_PTR_QCOM, | 
					 | 
				
			||||||
                              buf.len, &ion_cl, &err)); | 
					 | 
				
			||||||
  return buf; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void visionbuf_sync(const VisionBuf* buf, int dir) { | 
					 | 
				
			||||||
  int err; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  struct ion_fd_data fd_data = {0}; | 
					 | 
				
			||||||
  fd_data.fd = buf->fd; | 
					 | 
				
			||||||
  err = ioctl(ion_fd, ION_IOC_IMPORT, &fd_data); | 
					 | 
				
			||||||
  assert(err == 0); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  struct ion_flush_data flush_data = {0}; | 
					 | 
				
			||||||
  flush_data.handle = fd_data.handle; | 
					 | 
				
			||||||
  flush_data.vaddr = buf->addr; | 
					 | 
				
			||||||
  flush_data.offset = 0; | 
					 | 
				
			||||||
  flush_data.length = buf->len; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // ION_IOC_INV_CACHES ~= DMA_FROM_DEVICE
 | 
					 | 
				
			||||||
  // ION_IOC_CLEAN_CACHES ~= DMA_TO_DEVICE
 | 
					 | 
				
			||||||
  // ION_IOC_CLEAN_INV_CACHES ~= DMA_BIDIRECTIONAL
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  struct ion_custom_data custom_data = {0}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (dir) { | 
					 | 
				
			||||||
  case VISIONBUF_SYNC_FROM_DEVICE: | 
					 | 
				
			||||||
    custom_data.cmd = ION_IOC_INV_CACHES; | 
					 | 
				
			||||||
    break; | 
					 | 
				
			||||||
  case VISIONBUF_SYNC_TO_DEVICE: | 
					 | 
				
			||||||
    custom_data.cmd = ION_IOC_CLEAN_CACHES; | 
					 | 
				
			||||||
    break; | 
					 | 
				
			||||||
  default: | 
					 | 
				
			||||||
    assert(0); | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  custom_data.arg = (unsigned long)&flush_data; | 
					 | 
				
			||||||
  err = ioctl(ion_fd, ION_IOC_CUSTOM, &custom_data); | 
					 | 
				
			||||||
  assert(err == 0); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  struct ion_handle_data handle_data = {0}; | 
					 | 
				
			||||||
  handle_data.handle = fd_data.handle; | 
					 | 
				
			||||||
  err = ioctl(ion_fd, ION_IOC_FREE, &handle_data); | 
					 | 
				
			||||||
  assert(err == 0); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void visionbuf_free(const VisionBuf* buf) { | 
					 | 
				
			||||||
  if (buf->buf_cl) { | 
					 | 
				
			||||||
    CL_CHECK(clReleaseMemObject(buf->buf_cl)); | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
  munmap(buf->addr, buf->mmap_len); | 
					 | 
				
			||||||
  close(buf->fd); | 
					 | 
				
			||||||
  struct ion_handle_data handle_data = { | 
					 | 
				
			||||||
    .handle = buf->handle, | 
					 | 
				
			||||||
  }; | 
					 | 
				
			||||||
  int ret = ioctl(ion_fd, ION_IOC_FREE, &handle_data); | 
					 | 
				
			||||||
  assert(ret == 0); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,196 +0,0 @@ | 
				
			|||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <stdbool.h> | 
					 | 
				
			||||||
#include <string.h> | 
					 | 
				
			||||||
#include <unistd.h> | 
					 | 
				
			||||||
#include <assert.h> | 
					 | 
				
			||||||
#include <errno.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <sys/mman.h> | 
					 | 
				
			||||||
#include <sys/socket.h> | 
					 | 
				
			||||||
#include <sys/un.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ipc.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "visionipc.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct VisionPacketWire { | 
					 | 
				
			||||||
  int type; | 
					 | 
				
			||||||
  VisionPacketData d; | 
					 | 
				
			||||||
} VisionPacketWire; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int vipc_connect() { | 
					 | 
				
			||||||
  return ipc_connect(VIPC_SOCKET_PATH); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int vipc_recv(int fd, VisionPacket *out_p) { | 
					 | 
				
			||||||
  VisionPacketWire p = {0}; | 
					 | 
				
			||||||
  VisionPacket p2 = {0}; | 
					 | 
				
			||||||
  int ret = ipc_sendrecv_with_fds(false, fd, &p, sizeof(p), (int*)p2.fds, VIPC_MAX_FDS, &p2.num_fds); | 
					 | 
				
			||||||
  if (ret < 0) { | 
					 | 
				
			||||||
    printf("vipc_recv err: %s\n", strerror(errno)); | 
					 | 
				
			||||||
  } else { | 
					 | 
				
			||||||
    p2.type = p.type; | 
					 | 
				
			||||||
    p2.d = p.d; | 
					 | 
				
			||||||
    *out_p = p2; | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
  //printf("%d = vipc_recv(%d, %d): %d %d %d %zu\n", ret, fd, p2.num_fds, out_p->d.stream_bufs.type, out_p->d.stream_bufs.width, out_p->d.stream_bufs.height, out_p->d.stream_bufs.buf_len);
 | 
					 | 
				
			||||||
  return ret; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int vipc_send(int fd, const VisionPacket *p2) { | 
					 | 
				
			||||||
  assert(p2->num_fds <= VIPC_MAX_FDS); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  VisionPacketWire p = { | 
					 | 
				
			||||||
    .type = p2->type, | 
					 | 
				
			||||||
    .d = p2->d, | 
					 | 
				
			||||||
  }; | 
					 | 
				
			||||||
  int ret = ipc_sendrecv_with_fds(true, fd, (void*)&p, sizeof(p), (int*)p2->fds, p2->num_fds, NULL); | 
					 | 
				
			||||||
  //printf("%d = vipc_send(%d, %d): %d %d %d %zu\n", ret, fd, p2->num_fds, p2->d.stream_bufs.type, p2->d.stream_bufs.width, p2->d.stream_bufs.height, p2->d.stream_bufs.buf_len);
 | 
					 | 
				
			||||||
  return ret; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void vipc_bufs_load(VIPCBuf *bufs, const VisionStreamBufs *stream_bufs, | 
					 | 
				
			||||||
                     int num_fds, const int* fds) { | 
					 | 
				
			||||||
  for (int i=0; i<num_fds; i++) { | 
					 | 
				
			||||||
    if (bufs[i].addr) { | 
					 | 
				
			||||||
      munmap(bufs[i].addr, bufs[i].len); | 
					 | 
				
			||||||
      bufs[i].addr = NULL; | 
					 | 
				
			||||||
      close(bufs[i].fd); | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
    bufs[i].fd = fds[i]; | 
					 | 
				
			||||||
    bufs[i].len = stream_bufs->buf_len; | 
					 | 
				
			||||||
    bufs[i].addr = mmap(NULL, bufs[i].len, | 
					 | 
				
			||||||
                        PROT_READ | PROT_WRITE, | 
					 | 
				
			||||||
                        MAP_SHARED, bufs[i].fd, 0); | 
					 | 
				
			||||||
    // printf("b %d %zu -> %p\n", bufs[i].fd, bufs[i].len, bufs[i].addr);
 | 
					 | 
				
			||||||
    assert(bufs[i].addr != MAP_FAILED); | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int visionstream_init(VisionStream *s, VisionStreamType type, bool tbuffer, VisionStreamBufs *out_bufs_info) { | 
					 | 
				
			||||||
  int err; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  memset(s, 0, sizeof(*s)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  s->last_idx = -1; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  s->ipc_fd = vipc_connect(); | 
					 | 
				
			||||||
  if (s->ipc_fd < 0) return -1; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  VisionPacket p = { | 
					 | 
				
			||||||
    .type = VIPC_STREAM_SUBSCRIBE, | 
					 | 
				
			||||||
    .d = { .stream_sub = { | 
					 | 
				
			||||||
      .type = type, | 
					 | 
				
			||||||
      .tbuffer = tbuffer, | 
					 | 
				
			||||||
    }, }, | 
					 | 
				
			||||||
  }; | 
					 | 
				
			||||||
  err = vipc_send(s->ipc_fd, &p); | 
					 | 
				
			||||||
  if (err < 0) { | 
					 | 
				
			||||||
    close(s->ipc_fd); | 
					 | 
				
			||||||
    s->ipc_fd = -1; | 
					 | 
				
			||||||
    return -1; | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  VisionPacket rp; | 
					 | 
				
			||||||
  err = vipc_recv(s->ipc_fd, &rp); | 
					 | 
				
			||||||
  if (err <= 0) { | 
					 | 
				
			||||||
    close(s->ipc_fd); | 
					 | 
				
			||||||
    s->ipc_fd = -1; | 
					 | 
				
			||||||
    return -1; | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
  assert(rp.type == VIPC_STREAM_BUFS); | 
					 | 
				
			||||||
  assert(rp.d.stream_bufs.type == type); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  s->bufs_info = rp.d.stream_bufs; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  s->num_bufs = rp.num_fds; | 
					 | 
				
			||||||
  s->bufs = calloc(s->num_bufs, sizeof(VIPCBuf)); | 
					 | 
				
			||||||
  assert(s->bufs); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  vipc_bufs_load(s->bufs, &rp.d.stream_bufs, s->num_bufs, rp.fds); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (out_bufs_info) { | 
					 | 
				
			||||||
    *out_bufs_info = s->bufs_info; | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return 0; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void visionstream_release(VisionStream *s) { | 
					 | 
				
			||||||
  int err; | 
					 | 
				
			||||||
  if (s->last_idx >= 0) { | 
					 | 
				
			||||||
    VisionPacket rep = { | 
					 | 
				
			||||||
      .type = VIPC_STREAM_RELEASE, | 
					 | 
				
			||||||
      .d = { .stream_rel = { | 
					 | 
				
			||||||
        .type = s->last_type, | 
					 | 
				
			||||||
        .idx = s->last_idx, | 
					 | 
				
			||||||
      }} | 
					 | 
				
			||||||
    }; | 
					 | 
				
			||||||
    err = vipc_send(s->ipc_fd, &rep); | 
					 | 
				
			||||||
    s->last_idx = -1; | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
VIPCBuf* visionstream_get(VisionStream *s, VIPCBufExtra *out_extra) { | 
					 | 
				
			||||||
  int err; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  VisionPacket rp; | 
					 | 
				
			||||||
  err = vipc_recv(s->ipc_fd, &rp); | 
					 | 
				
			||||||
  if (err <= 0) { | 
					 | 
				
			||||||
    return NULL; | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
  assert(rp.type == VIPC_STREAM_ACQUIRE); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (s->last_idx >= 0) { | 
					 | 
				
			||||||
    VisionPacket rep = { | 
					 | 
				
			||||||
      .type = VIPC_STREAM_RELEASE, | 
					 | 
				
			||||||
      .d = { .stream_rel = { | 
					 | 
				
			||||||
        .type = s->last_type, | 
					 | 
				
			||||||
        .idx = s->last_idx, | 
					 | 
				
			||||||
      }} | 
					 | 
				
			||||||
    }; | 
					 | 
				
			||||||
    err = vipc_send(s->ipc_fd, &rep); | 
					 | 
				
			||||||
    if (err <= 0) { | 
					 | 
				
			||||||
      return NULL; | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  s->last_type = rp.d.stream_acq.type; | 
					 | 
				
			||||||
  s->last_idx = rp.d.stream_acq.idx; | 
					 | 
				
			||||||
  assert(s->last_idx < s->num_bufs); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (out_extra) { | 
					 | 
				
			||||||
    *out_extra = rp.d.stream_acq.extra; | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return &s->bufs[s->last_idx]; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void visionstream_destroy(VisionStream *s) { | 
					 | 
				
			||||||
  int err; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (s->last_idx >= 0) { | 
					 | 
				
			||||||
    VisionPacket rep = { | 
					 | 
				
			||||||
      .type = VIPC_STREAM_RELEASE, | 
					 | 
				
			||||||
      .d = { .stream_rel = { | 
					 | 
				
			||||||
        .type = s->last_type, | 
					 | 
				
			||||||
        .idx = s->last_idx, | 
					 | 
				
			||||||
      }} | 
					 | 
				
			||||||
    }; | 
					 | 
				
			||||||
    err = vipc_send(s->ipc_fd, &rep); | 
					 | 
				
			||||||
    s->last_idx = -1; | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (int i=0; i<s->num_bufs; i++) { | 
					 | 
				
			||||||
    if (s->bufs[i].addr) { | 
					 | 
				
			||||||
      munmap(s->bufs[i].addr, s->bufs[i].len); | 
					 | 
				
			||||||
      s->bufs[i].addr = NULL; | 
					 | 
				
			||||||
      close(s->bufs[i].fd); | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
  } | 
					 | 
				
			||||||
  if (s->bufs) free(s->bufs); | 
					 | 
				
			||||||
  if (s->ipc_fd >= 0) close(s->ipc_fd); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,120 +0,0 @@ | 
				
			|||||||
#ifndef VISIONIPC_H | 
					 | 
				
			||||||
#define VISIONIPC_H | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stddef.h> | 
					 | 
				
			||||||
#include <stdint.h> | 
					 | 
				
			||||||
#include <stdbool.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define VIPC_SOCKET_PATH "/tmp/vision_socket" | 
					 | 
				
			||||||
#define VIPC_MAX_FDS 64 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __cplusplus | 
					 | 
				
			||||||
extern "C" { | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef enum VisionIPCPacketType { | 
					 | 
				
			||||||
  VIPC_INVALID = 0, | 
					 | 
				
			||||||
  VIPC_STREAM_SUBSCRIBE, | 
					 | 
				
			||||||
  VIPC_STREAM_BUFS, | 
					 | 
				
			||||||
  VIPC_STREAM_ACQUIRE, | 
					 | 
				
			||||||
  VIPC_STREAM_RELEASE, | 
					 | 
				
			||||||
} VisionIPCPacketType; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef enum VisionStreamType { | 
					 | 
				
			||||||
  VISION_STREAM_RGB_BACK, | 
					 | 
				
			||||||
  VISION_STREAM_RGB_FRONT, | 
					 | 
				
			||||||
  VISION_STREAM_RGB_WIDE, | 
					 | 
				
			||||||
  VISION_STREAM_YUV, | 
					 | 
				
			||||||
  VISION_STREAM_YUV_FRONT, | 
					 | 
				
			||||||
  VISION_STREAM_YUV_WIDE, | 
					 | 
				
			||||||
  VISION_STREAM_MAX, | 
					 | 
				
			||||||
} VisionStreamType; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct VisionUIInfo { | 
					 | 
				
			||||||
  int big_box_x, big_box_y; | 
					 | 
				
			||||||
  int big_box_width, big_box_height; | 
					 | 
				
			||||||
  int transformed_width, transformed_height; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int front_box_x, front_box_y; | 
					 | 
				
			||||||
  int front_box_width, front_box_height; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int wide_box_x, wide_box_y; | 
					 | 
				
			||||||
  int wide_box_width, wide_box_height; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} VisionUIInfo; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct VisionStreamBufs { | 
					 | 
				
			||||||
  VisionStreamType type; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int width, height, stride; | 
					 | 
				
			||||||
  size_t buf_len; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  union { | 
					 | 
				
			||||||
    VisionUIInfo ui_info; | 
					 | 
				
			||||||
  } buf_info; | 
					 | 
				
			||||||
} VisionStreamBufs; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct VIPCBufExtra { | 
					 | 
				
			||||||
  // only for yuv
 | 
					 | 
				
			||||||
  uint32_t frame_id; | 
					 | 
				
			||||||
  uint64_t timestamp_sof; | 
					 | 
				
			||||||
  uint64_t timestamp_eof; | 
					 | 
				
			||||||
} VIPCBufExtra; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef union VisionPacketData { | 
					 | 
				
			||||||
  struct { | 
					 | 
				
			||||||
    VisionStreamType type; | 
					 | 
				
			||||||
    bool tbuffer; | 
					 | 
				
			||||||
  } stream_sub; | 
					 | 
				
			||||||
  VisionStreamBufs stream_bufs; | 
					 | 
				
			||||||
  struct { | 
					 | 
				
			||||||
    VisionStreamType type; | 
					 | 
				
			||||||
    int idx; | 
					 | 
				
			||||||
    VIPCBufExtra extra; | 
					 | 
				
			||||||
  } stream_acq; | 
					 | 
				
			||||||
  struct { | 
					 | 
				
			||||||
    VisionStreamType type; | 
					 | 
				
			||||||
    int idx; | 
					 | 
				
			||||||
  } stream_rel; | 
					 | 
				
			||||||
} VisionPacketData; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct VisionPacket { | 
					 | 
				
			||||||
  int type; | 
					 | 
				
			||||||
  VisionPacketData d; | 
					 | 
				
			||||||
  int num_fds; | 
					 | 
				
			||||||
  int fds[VIPC_MAX_FDS]; | 
					 | 
				
			||||||
} VisionPacket; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int vipc_connect(void); | 
					 | 
				
			||||||
int vipc_recv(int fd, VisionPacket *out_p); | 
					 | 
				
			||||||
int vipc_send(int fd, const VisionPacket *p); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct VIPCBuf { | 
					 | 
				
			||||||
  int fd; | 
					 | 
				
			||||||
  size_t len; | 
					 | 
				
			||||||
  void* addr; | 
					 | 
				
			||||||
} VIPCBuf; | 
					 | 
				
			||||||
void vipc_bufs_load(VIPCBuf *bufs, const VisionStreamBufs *stream_bufs, | 
					 | 
				
			||||||
                     int num_fds, const int* fds); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct VisionStream { | 
					 | 
				
			||||||
  int ipc_fd; | 
					 | 
				
			||||||
  int last_idx; | 
					 | 
				
			||||||
  int last_type; | 
					 | 
				
			||||||
  int num_bufs; | 
					 | 
				
			||||||
  VisionStreamBufs bufs_info; | 
					 | 
				
			||||||
  VIPCBuf *bufs; | 
					 | 
				
			||||||
} VisionStream; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int visionstream_init(VisionStream *s, VisionStreamType type, bool tbuffer, VisionStreamBufs *out_bufs_info); | 
					 | 
				
			||||||
void visionstream_release(VisionStream *s); | 
					 | 
				
			||||||
VIPCBuf* visionstream_get(VisionStream *s, VIPCBufExtra *out_extra); | 
					 | 
				
			||||||
void visionstream_destroy(VisionStream *s); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __cplusplus | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif | 
					 | 
				
			||||||
					Loading…
					
					
				
		Reference in new issue