// Program to illustrate thread-related memory leak in the ZWO SDK running on linux with an ASI120MM camera.
// Compile with:
// g++ -Wall -Werror -g -c -o bugfix.o bugfix.cc
// g++ -o bugfix bugfix.o libASICamera2.a -lusb-1.0 -ldl
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "./ASICamera2.h"
#include <pthread.h>
#include <dlfcn.h>
// Intercept calls to pthread_create() and apply PTHREAD_CREATE_DETACHED attribute.
//
typedef int (*PTHREAD_CREATE )(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
static int (*actual_pthread_create)(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
int pthread_create (pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg)
{
printf("create\n");
#if 1 // 1=apply bugfix, 0=don't
static pthread_attr_t new_attr;
pthread_attr_setdetachstate(&new_attr, PTHREAD_CREATE_DETACHED);
attr = &new_attr;
#endif
return actual_pthread_create(thread, attr, start_routine, arg);
}
// Intercept calls to pthread_join() and report them.
//
typedef int (*PTHREAD_JOIN )(pthread_t thread, void **retval);
static int (*actual_pthread_join)(pthread_t thread, void **retval);
int pthread_join (pthread_t thread, void **retval)
{
printf("join\n");
int rc = actual_pthread_join(thread, retval);
return rc;
}
// Install function hooks.
//
void
bugfix_init()
{
printf("installing hooks\n");
if (!(actual_pthread_create = (PTHREAD_CREATE)dlsym(RTLD_NEXT, "pthread_create")))
{
printf("bad dlsym");
exit(1);
}
if (!(actual_pthread_join = (PTHREAD_JOIN)dlsym(RTLD_NEXT, "pthread_join")))
{
printf("bad dlsym");
exit(1);
}
}
int
main()
{
bugfix_init();
typedef unsigned char BYTE;
typedef unsigned short WORD;
int numDevices = ASIGetNumOfConnectedCameras();
if (numDevices <= 0)
{
printf("no camera\n");
exit(1);
}
if (numDevices != 1)
{
printf("unexpected cameras\n");
exit(1);
}
int cameraIndex = 0;
ASI_CAMERA_INFO info;
ASIGetCameraProperty(&info, cameraIndex);
int cameraId = info.CameraID;
if (ASIOpenCamera(cameraId) != ASI_SUCCESS)
{
printf("can't open camera\n");
exit(1);
}
int width = 1280; int height = 960; int binning = 1;
ASI_IMG_TYPE type = ASI_IMG_RAW16;
int num_pixels = width * height;
int bytes_per_pixel = 2;
if (ASISetROIFormat(cameraId, width, height, binning, type) != ASI_SUCCESS)
{
printf("can't set image format\n");
exit(1);
}
WORD *image = new WORD;
for (int cnt = 0;;)
{
ASIStartExposure(cameraId, ASI_FALSE);
ASI_EXPOSURE_STATUS status = ASI_EXP_WORKING;
while (status == ASI_EXP_WORKING)
{
usleep(100 * 1000);
ASIGetExpStatus(cameraId, &status);
}
if (status != ASI_EXP_SUCCESS)
{
printf("exposure failed\n");
exit(1);
}
if (ASIGetDataAfterExp(cameraId, (BYTE *)image, num_pixels * bytes_per_pixel) != ASI_SUCCESS)
{
printf("no data\n");
exit(1);
}
printf("===%d===\n", ++cnt), fflush(stdout);
// Here we display our program's memory size as it runs.
// We do it by parsing the output of the ps command, which looks similar to this:
//
// F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
// 0 S 1000 14015 14014 9 80 0 - 25916 hrtime pts/1 00 bug
// ^^^^^we print this field
char cmd;
snprintf(cmd, sizeof(cmd), "ps -l -p %d | tail -1 | awk '{ print $10 }'", getpid());
system(cmd);
}
return 0;
}