Updtaing a QProgressbar from a different Thread - file

I have developed my own hybrid stream cipher and for the GUI i am using Qt. Initially i wrote it on a single thread but it being a stream cipher was making GUI dysfunctional when operating on large files. So i shifted the encryption/decryption to a separate Qthread. Also to show the progress i included a standard QProgressbar onto the GUI. But when I run the File I/O the encryption/decryption works perfectly but the progress bar doesn't update properly. After the whole operation completes, the progress bar suddenly goes from 0% to 100% showing that it didn't get the chance to update during the operation. For the code, I emitted the completed percentage from the FileCrypto to the main GUI thread onto the QProgressbar's setValue(int) slot. Since it didn't work I also tried to sent a int poitner over to the FileCrypto thread whilst updating the pointer with the percentage and using a QTimer on the GUI thread to check the value of the int value locally and update the progress bar but still I got the exact same result.
Here is my code:
The FileCrypto class:
#include <QThread>
#include <QFile>
#include <PolyVernam.h> //my algo header
class FileCrypto : public QThread
{
Q_OBJECT
public:
FileCrypto(QString, QString, int);
bool stopIt;
protected:
void run();
signals:
void completed(int);
void msg(QString);
void pathMsg1(QString);
void pathMsg2(QString);
void keyMsg(QString);
private:
QFile src, dest;
QString tag;
int mode;
qint64 length;
PolyVernam pv;
};
The Code:
#include <FileCrypto.h>
FileCrypto::FileCrypto(QString input, QString keyFile, int mode)
{
stopIt = false;
this->mode = mode;
src.setFileName(input);
if(mode == 1)
{
emit msg("Current Encryption/Decryption status: Encrypting file... :D:D");
tag = "-encrypted";
pv.setMode("encrypt", "");
}
else
{
emit msg("Current Encryption/Decryption status: Decrypting file... :D:D");
tag = "-decrypted";
pv.setMode("decrypt", keyFile);
}
dest.setFileName(QFileInfo(src).absolutePath() + "/" + QFileInfo(src).baseName()
+ tag + "." + QFileInfo(src).completeSuffix());
length = src.bytesAvailable();
}
void FileCrypto::run()
{
qint64 done = 0;
quint8 r, outChar;
char ch;
QDataStream in(&src);
in.setVersion(QDataStream::Qt_4_7);
src.open(QIODevice::ReadOnly);
QDataStream out(&dest);
out.setVersion(QDataStream::Qt_4_7);
dest.open(QIODevice::WriteOnly);
while(!in.atEnd() && !stopIt)
{
done++;
in >> r;
ch = char(r);
if(mode == 1)
outChar = pv.encrypt(QString(ch)).at(0).toAscii();
else
outChar = pv.decrypt(QString(ch)).at(0).toAscii();
out << outChar;
emit completed(int((done / length) * 100));
}
src.close();
dest.close();
if(stopIt)
this->exit(0);
if(mode == 1)
{
emit pathMsg1(QFileInfo(src).absoluteFilePath());
emit pathMsg2(QFileInfo(dest).absoluteFilePath());
}
else
{
emit pathMsg1(QFileInfo(dest).absoluteFilePath());
emit pathMsg2(QFileInfo(src).absoluteFilePath());
}
emit keyMsg(pv.keyFilePath);
emit msg("Current Encryption/Decryption status: Idle... :'(");
}
This is how I am making the thread and connecting it on the main GUI thread:
FileCrypto *fc = new FileCrypto(ui->lineEdit_4->text(), "", 1);
connect(fc, SIGNAL(completed(int)), ui->progressBar, SLOT(setValue(int)));
connect(fc, SIGNAL(msg(QString)), ui->statusBar, SLOT(showMessage(QString)));
connect(fc, SIGNAL(pathMsg1(QString)), ui->lineEdit_4, SLOT(setText(QString)));
connect(fc, SIGNAL(pathMsg2(QString)), ui->lineEdit_5, SLOT(setText(QString)));
connect(fc, SIGNAL(keyMsg(QString)), ui->lineEdit_2, SLOT(setText(QString)));
connect(fc, SIGNAL(keyMsg(QString)), this, SLOT(done()));
If I don't update the progress bar i.e. don't emit the percentage, the process happens much faster. I also tried printing the percentage. It slows it down like hell but the values are fine. Also can you suggest a way to change it to buffered IO....
Any sort of help is much appreciated here.......

The problem does not lie in the fact that you are calling from a different thread. It is located in:
emit completed(int((done / length) * 100));
Since done and length are int types, and done <= length, done/length == 0. So change it to:
emit completed(100 * done / length);
(it can lead to arithmetic overflow).

Related

Event-based task management using FreeRTOS

I'm trying to pick up C, using an esp32. While looking at exactly how FreeRTOS works, I found the following page regarding how to use the tasks, and best practices etc.
https://www.freertos.org/implementing-a-FreeRTOS-task.html
According to this page, to prevent starvation, tasks should be event based. Regarding what I am trying to achieve, I will try to provide a very simplified example.
Background
I have a LCD screen, which should display data from a sensor. The data shown on the LCD will be done using a task, which according to the documentation, should never exit and should be event driven to prevent starvation.
I have a way of controlling the data shown on the LCD screen, which would be a rotary encoder. This encoder can be clicked, which should refresh the sensor's data.
Question
How would I implement the event based tasks, which are described on the FreeRTOS page, in this specific context? I had a look at the documentation and the "simple" example projects on their github, but as a beginner within C and embedded, they were extremely overwhelming.
Simple demo code
void update_sensor_task(void *pvParameters)
{
// Ensure the task keeps on running
for( ; ; )
{
if(event_update_sensor) // How would I be able to notify the task that this should be run?
{
// update the data
}
}
// Tasks should not be returning, but if they happen to do so, ensure a clean exit
vTaskDelete(NULL);
}
void screen_temperature_task(void *pvParameters)
{
for(; ;)
{
if(event_sensor_updated)
{
// Update the lcd screen with the new data
}
}
vTaskDelete(NULL);
}
void on_rotary_clicked(void *pvParameters)
{
// Notify the sensor task that it should be updating?
}
EDIT:
By using what has been marked as the correct answer, I have managed to get it to work by implementing it the following way:
/* Queue used to send and receive the data */
QueueHandle_t xStructQueue = NULL;
/* Struct which shall be used to hold and pass around the data for the LCD screen*/
struct LcdData
{
int current_temp;
int current_humidity;
} xLcdData;
void initialize_queues(void)
{
xLcdData.current_humidity = 0;
xLcdData.current_temp = 0;
xStructQueue = xQueueCreate(
/* The maximum number of items the queue can hold*/
5,
/* The size of each struct, which the queue should be able to hold */
sizeof( xLcdData )
);
if(xStructQueue == NULL)
{
ESP_LOGE(TAG, "Queue has not been initialized successfully");
}
}
void screen_temperature_task_simplified(void *pvParameters)
{
int counter = 0;
for(; ;)
{
struct LcdData xReceivedStructure;
BaseType_t result;
result = xQueueReceive(xStructQueue, &xReceivedStructure, ( TickType_t ) 10);
if(result == pdPASS)
{
counter = counter + 1;
char snum_current_counter[12];
sprintf(snum_current_counter, "%d", counter);
i2c_lcd1602_clear (lcd_info);
i2c_lcd1602_write_string (lcd_info, snum_current_counter);
}
}
vTaskDelete(NULL);
}
void update_sensor_struct(void)
{
xLcdData.current_temp = DHT11_read().temperature;
xLcdData.current_humidity = DHT11_read().humidity;
// Log the results in the console
printf("Temperature is %d \n", xLcdData.current_temp);
printf("Humidity is %d\n", xLcdData.current_humidity);
ESP_LOGI(TAG, "Data has been updated");
}
void on_rotary_clicked_simplified()
{
ESP_LOGI(TAG, "Rotary encoder has been clicked!");
// Update the struct which holds the data
update_sensor_struct();
/* Send the entire struct to the queue */
xQueueSend(
/* The handle of the queue */
xStructQueue,
/* The adress of the struct which should be sent */
(void *) &xLcdData,
/* Block time of 0 says don't block if the queue is already full.
Check the value returned by xQueueSend() to know if the message
was sent to the queue successfully. */
( TickType_t ) 0
);
}
I use FRTOS and event driven development.
The typical flow here would be:
for(;;)
{
BaseType_t result;
result = xQueueReceive(LCD_Event_Queue, &someLCDEvent, QUEUE_TIMEOUT);
if (result == pdPASS)
{
/* We have new event data in someLCDEvent; Use that data to update the LCD */
}
else
{
/* No new event, do some brief idle-time processing if necessary */
}
}
In brief, wait up to QUEUE_TIMEOUT time for a new event to arrive.
If a new event arrives within that timeframe successfully, then process the data in that event and update your screen.
If a new event does not arrive, you have an opportunity to do some other maintenance work.
Designing and defining the structure-type of someLCDEvent, and putting data into the queue is a big topic, and will depend a lot on your specific project.

X-DWM -- help me fix a bug in C source code

I am using dwm (6.2) window manager and I found a bug which I would love to solve.
Window manager uses "master area" and "stack area" where windows are put:
It is possible to move window at the top of the "stack area" to the bottom of the "master area" using ALT + i. It is also possible to move windows from the bottom of the "master area" back to the top of "stack area" using ALT + d.
Now in this case, if I use ALT + i, layout changes and after the key combination there are two windows in the "master area":
I repeat it again and now there are three windows in the "master area":
I repeat it yet again and now there are three windows in the "master area" which has 100% width:
If I would at this point decide to return windows from the "master area" to the "stack area" I would start pressing ALT + d and windows would imediately return back to the "stack area". This works okay.
But I intentionaly make a mistake and instead press ALT + i again for example three more times. It looks like nothing happens...
But now if I try to return windows from the "master area" to the "stack area" I first need to press ALT + d three more times and nothing will happen! And then finaly, when I press ALT + d for the fourth time, window manager will return the first window from the bottom of the "master area" to the top of the "stack area".
So this is not well thought out and should be considered a bug...
There must be some sort of a counter in the source code which was incremented three more times by pressing ALT + i but it should not increase after all windows are already in the "master area".
In config.def.h source file (www) there is a part of the code where keys are assigned. And here I can see that when user presses ALT + i function incnmaster() is called and is passed an argument .i = +1 (I don't understand this argument).
static Key keys[] = {
/* modifier key function argument */
...
{ MODKEY, XK_i, incnmaster, {.i = +1 } },
{ MODKEY, XK_d, incnmaster, {.i = -1 } },
...
};
Key is a structure inside dwm.c source file (www):
typedef struct {
unsigned int mod;
KeySym keysym;
void (*func)(const Arg *);
const Arg arg;
} Key;
Function incnmaster() is defined in dwm.c source file (www):
void
incnmaster(const Arg *arg)
{
selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
arrange(selmon);
}
where arg is a pointer to Arg (Arg*) which is a union (I don't quite understand how to deal with the argument .i = +1):
typedef union {
int i;
unsigned int ui;
float f;
const void *v;
} Arg;
selmon is a structure Monitor:
struct Monitor {
char ltsymbol[16];
float mfact;
int nmaster;
int num;
int by; /* bar geometry */
int mx, my, mw, mh; /* screen size */
int wx, wy, ww, wh; /* window area */
unsigned int seltags;
unsigned int sellt;
unsigned int tagset[2];
int showbar;
int topbar;
Client *clients;
Client *sel;
Client *stack;
Monitor *next;
Window barwin;
const Layout *lt[2];
};
MAX is defined in a separate source file util.h (www) as:
#define MAX(A, B) ((A) > (B) ? (A) : (B))
and function arrange() is defined like this:
void
arrange(Monitor *m)
{
if (m)
showhide(m->stack);
else for (m = mons; m; m = m->next)
showhide(m->stack);
if (m) {
arrangemon(m);
restack(m);
} else for (m = mons; m; m = m->next)
arrangemon(m);
}
I don't think I have to dig any further...
Now I think I need to implement some sort of an if sentantce in the C code to prevent selmon->nmaster to increase too much, but I am a bit confused. Can anyone help?
Why are you holding number of clients when it's linked list? You cant obtain number of clients on demand. Similar code can be found monocle count patch. If you really have to keep that count yourself (for performance reasons), I would look at any place where is Client list modified by dwm and project that modification to counter.
Structure Client contains pointer to a "next" Client, implementation may depend on whenever you want to use multihead support, but using code similar to Client* c = nexttiled(c->next), where first reference can be obtained from Monitor by calling Client* c = nexttiled(monitor->clients). It you count these in loop that should be enough.
If you want to still keep count yourself, I would find functions within dwm.c working with Client (detach, attach, ...) and find which are modifying list where you can increment/decrement counter based on executed operation.
Nobody answered before I could figure this one out myself. Problem is that Suckless team never implemented any kind of mechanism to count a number of opened windows (they call them clients). This is why I added a int nclients; member to struct Monitor:
struct Monitor {
char ltsymbol[16];
float mfact;
int nmaster;
int nclients;
int num;
int by; /* bar geometry */
int mx, my, mw, mh; /* screen size */
int wx, wy, ww, wh; /* window area */
unsigned int seltags;
unsigned int sellt;
unsigned int tagset[2];
int showbar;
int topbar;
Client *clients;
Client *sel;
Client *stack;
Monitor *next;
Window barwin;
const Layout *lt[2];
};
And then I made sure it is initialized to 0 at boot time by adding m->nclients = 0; in createmon() function which I guessed is ran at the beginning:
Monitor *
createmon(void)
{
Monitor *m;
m = ecalloc(1, sizeof(Monitor));
m->tagset[0] = m->tagset[1] = 1;
m->mfact = mfact;
m->nmaster = nmaster;
m->nclients = 0;
m->showbar = showbar;
m->topbar = topbar;
m->gappx = gappx;
m->lt[0] = &layouts[0];
m->lt[1] = &layouts[1 % LENGTH(layouts)];
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
return m;
}
Then I made sure that my counter nclients is increased when new window appears. I added ++selmon->nclients; and arrange(selmon); (to be able to move clients to stack/master imediately after you close one of them) statement at the beginning of the spawn() function:
void
spawn(const Arg *arg)
{
++selmon->nclients;
arrange(selmon);
if (arg->v == dmenucmd)
dmenumon[0] = '0' + selmon->num;
if (fork() == 0) {
if (dpy)
close(ConnectionNumber(dpy));
setsid();
execvp(((char **)arg->v)[0], (char **)arg->v);
fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
perror(" failed");
exit(EXIT_SUCCESS);
}
}
Counter should be decreased when window is closed. This is why I added a --selmon->nclients; and arrange(selmon); (to be able to move clients to stack/master imediately after you close one of them) at the top of the killclient() function:
void
killclient(const Arg *arg)
{
--selmon->nclients;
arrange(selmon);
if (!selmon->sel)
return;
if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) {
XGrabServer(dpy);
XSetErrorHandler(xerrordummy);
XSetCloseDownMode(dpy, DestroyAll);
XKillClient(dpy, selmon->sel->win);
XSync(dpy, False);
XSetErrorHandler(xerror);
XUngrabServer(dpy);
}
}
Now that the counter was set up, I could use it to rewrite incnmaster() function like this:
void
incnmaster(const Arg *arg)
{
if((arg->i > 0) && (selmon->nmaster < selmon->nclients)){
++selmon->nmaster;
}
if((arg->i < 0) && (selmon->nmaster > 0)){
--selmon->nmaster;
}
arrange(selmon);
}
Pay attention. My DWM is a bit patched, so some lines might be a bit
different than yours, but just stick to the same philosophy and you
can fix this.
This solution partialy works. It only fails to work when I:
A. use dmenu
dmenu when started can (a) open a client or (b) do nothing. In case (a) everything works as expected, but in case (b) nmaster and nclients become out of sync again.
So for example if I do scenario (b) once and use CTRL+i endless times, I will have to use CTRL+d once and nothing will happen, but if I use it once more one window is moved from master to stack area.
B. run any kind of windowed application from a terminal
It looks like DWM can't keep track of windows that are run from a terminal and treats them in a wrong way... In this case as well nmaster and nclients become out of sync.
Does anyone know if there is any other function besides spawn that is executed when any kind of window is opened?
This is still not solved!

String array not deallocated upon scope exit

I am running into some serious memory leaks in my application, so I setup this extremely bare solution to test what happens when a String array goes out of scope...
I know that the old TextString implementation of String was lacking a destructor, but this current implementation seems to have it.
I am using this MemoryFree library (Note this linked code has now been fixed based on the accepted answer to this question).
The code examines two scenarios: Allocation of char array and string array in two different functions to force scope exit on both.
#include <MemoryFree.h>
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
int freeBefore, freeAfter;
//TEST ALLOCATION OF CHAR ARRAY//
freeBefore = freeMemory();
AllocateCharArr();
freeAfter = freeMemory();
Serial.println("CHAR*: Before " + String(freeBefore)
+ ", After " + String(freeAfter)
+ ", Diff " + String(freeBefore - freeAfter));
//TEST ALLOCATION OF STRING//
freeBefore = freeMemory();
AllocateStringArr();
freeAfter = freeMemory();
Serial.println("STRING: Before " + String(freeBefore)
+ ", After " + String(freeAfter)
+ ", Diff " + String(freeBefore - freeAfter));
}
void AllocateCharArr() {
char s[100];
}
void AllocateStringArr() {
String s[100];
}
void loop() { /* empty */ }
Output:
CHAR*: Before 1710, After 1710, Diff 0
STRING: Before 1645, After 1309, Diff 336
How come the String array allocation is not wiped from memory?
I have come across memory handling issues in Arduino versions prior to 1.0 when testing the String class (see forum post here).
The String constructor uses realloc internally and it's this (avr libc) dynamic memory handling that was causing the problems (due to the pointer to the top of the heap __brkval not being updated upon free()).
Run the following code to see these issues in versions 0023, 0022, etc. In Arduino 1.0 the code should show no memory leaks:
#if (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
#include <HardwareSerial.h>
#include <MemoryFree.h>
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
int freeBefore, freeAfter;
freeBefore = freeMemory();
void* buffer = malloc(10);
if (buffer == 0) {
Serial.println("Failed to allocate memory");
}
free(buffer);
freeAfter = freeMemory();
Serial.println("Before " + String(freeBefore)
+ ", After " + String(freeAfter)
+ ", Diff " + String(freeBefore - freeAfter));
}
void loop() {
}
In addition, the MemoryFree library you are using can give wrong results as it doesn't take into account the free list. Try this updated version of MemoryFree.cpp:
extern unsigned int __heap_start;
extern void *__brkval;
/*
* The free list structure as maintained by the
* avr-libc memory allocation routines.
*/
struct __freelist {
size_t sz;
struct __freelist *nx;
};
/* The head of the free list structure */
extern struct __freelist *__flp;
#include "MemoryFree.h";
/* Calculates the size of the free list */
int freeListSize() {
struct __freelist* current;
int total = 0;
for (current = __flp; current; current = current->nx) {
total += 2; /* Add two bytes for the memory block's header */
total += (int) current->sz;
}
return total;
}
int freeMemory() {
int free_memory;
if ((int)__brkval == 0) {
free_memory = ((int)&free_memory) - ((int)&__heap_start);
} else {
free_memory = ((int)&free_memory) - ((int)__brkval);
free_memory += freeListSize();
}
return free_memory;
}
If you look through the Arduino source, you might come across the file ".\arduino-1.0\hardware\arduino\cores\arduino\WString.cpp". In this file, I noticed that String does not have a default (parameterless) constructor. Perhaps this could be the problem? Doubtful, but anyway, the source should help. Best of luck.
Comment out the line String s[100]; and see if you get different results. It looks like the memory allocations you're seeing are due to the string operations in your setup() function, not to the declaration of a local array of strings in AllocateStrArr(). You can take a look at WString.cpp and WString.h to see that operator+ has been overridden, so every call to String() or concatenation using + could create another object.

tmpfile() on windows 7 x64

Running the following code on Windows 7 x64
#include <stdio.h>
#include <errno.h>
int main() {
int i;
FILE *tmp;
for (i = 0; i < 10000; i++) {
errno = 0;
if(!(tmp = tmpfile())) printf("Fail %d, err %d\n", i, errno);
fclose(tmp);
}
return 0;
}
Gives errno 13 (Permission denied), on the 637th and 1004th call, it works fine on XP (haven't tried 7 x86). Am I missing something or is this a bug?
I've got similar problem on Windows 8 - tmpfile() was causing win32 ERROR_ACCESS_DENIED error code - and yes, if you run application with administrator privileges - then it works fine.
I guess problem is mentioned over here:
https://lists.gnu.org/archive/html/bug-gnulib/2007-02/msg00162.html
Under Windows, the tmpfile function is defined to always create
its temporary file in the root directory. Most users don't have
permission to do that, so it will often fail.
I would suspect that this is kinda incomplete windows port issue - so this should be an error reported to Microsoft. (Why to code tmpfile function if it's useless ?)
But who have time to fight with Microsoft wind mills ?! :-)
I've coded similar implementation using GetTempPathW / GetModuleFileNameW / _wfopen. Code where I've encountered this problem came from libjpeg - I'm attaching whole source code here, but you can pick up code from jpeg_open_backing_store.
jmemwin.cpp:
//
// Windows port for jpeg lib functions.
//
#define JPEG_INTERNALS
#include <Windows.h> // GetTempFileName
#undef FAR // Will be redefined - disable warning
#include "jinclude.h"
#include "jpeglib.h"
extern "C" {
#include "jmemsys.h" // jpeg_ api interface.
//
// Memory allocation and freeing are controlled by the regular library routines malloc() and free().
//
GLOBAL(void *) jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
{
return (void *) malloc(sizeofobject);
}
GLOBAL(void) jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
{
free(object);
}
/*
* "Large" objects are treated the same as "small" ones.
* NB: although we include FAR keywords in the routine declarations,
* this file won't actually work in 80x86 small/medium model; at least,
* you probably won't be able to process useful-size images in only 64KB.
*/
GLOBAL(void FAR *) jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
{
return (void FAR *) malloc(sizeofobject);
}
GLOBAL(void) jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
{
free(object);
}
//
// Used only by command line applications, not by static library compilation
//
#ifndef DEFAULT_MAX_MEM /* so can override from makefile */
#define DEFAULT_MAX_MEM 1000000L /* default: one megabyte */
#endif
GLOBAL(long) jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, long max_bytes_needed, long already_allocated)
{
// jmemansi.c's jpeg_mem_available implementation was insufficient for some of .jpg loads.
MEMORYSTATUSEX status = { 0 };
status.dwLength = sizeof(status);
GlobalMemoryStatusEx(&status);
if( status.ullAvailPhys > LONG_MAX )
// Normally goes here since new PC's have more than 4 Gb of ram.
return LONG_MAX;
return (long) status.ullAvailPhys;
}
/*
Backing store (temporary file) management.
Backing store objects are only used when the value returned by
jpeg_mem_available is less than the total space needed. You can dispense
with these routines if you have plenty of virtual memory; see jmemnobs.c.
*/
METHODDEF(void) read_backing_store (j_common_ptr cinfo, backing_store_ptr info, void FAR * buffer_address, long file_offset, long byte_count)
{
if (fseek(info->temp_file, file_offset, SEEK_SET))
ERREXIT(cinfo, JERR_TFILE_SEEK);
size_t readed = fread( buffer_address, 1, byte_count, info->temp_file);
if (readed != (size_t) byte_count)
ERREXIT(cinfo, JERR_TFILE_READ);
}
METHODDEF(void)
write_backing_store (j_common_ptr cinfo, backing_store_ptr info, void FAR * buffer_address, long file_offset, long byte_count)
{
if (fseek(info->temp_file, file_offset, SEEK_SET))
ERREXIT(cinfo, JERR_TFILE_SEEK);
if (JFWRITE(info->temp_file, buffer_address, byte_count) != (size_t) byte_count)
ERREXIT(cinfo, JERR_TFILE_WRITE);
// E.g. if you need to debug writes.
//if( fflush(info->temp_file) != 0 )
// ERREXIT(cinfo, JERR_TFILE_WRITE);
}
METHODDEF(void)
close_backing_store (j_common_ptr cinfo, backing_store_ptr info)
{
fclose(info->temp_file);
// File is deleted using 'D' flag on open.
}
static HMODULE DllHandle()
{
MEMORY_BASIC_INFORMATION info;
VirtualQuery(DllHandle, &info, sizeof(MEMORY_BASIC_INFORMATION));
return (HMODULE)info.AllocationBase;
}
GLOBAL(void) jpeg_open_backing_store(j_common_ptr cinfo, backing_store_ptr info, long total_bytes_needed)
{
// Generate unique filename.
wchar_t path[ MAX_PATH ] = { 0 };
wchar_t dllPath[ MAX_PATH ] = { 0 };
GetTempPathW( MAX_PATH, path );
// Based on .exe or .dll filename
GetModuleFileNameW( DllHandle(), dllPath, MAX_PATH );
wchar_t* p = wcsrchr( dllPath, L'\\');
wchar_t* ext = wcsrchr( p + 1, L'.');
if( ext ) *ext = 0;
wchar_t* outFile = path + wcslen(path);
static int iTempFileId = 1;
// Based on process id (so processes would not fight with each other)
// Based on some process global id.
wsprintfW(outFile, L"%s_%d_%d.tmp",p + 1, GetCurrentProcessId(), iTempFileId++ );
// 'D' - temporary file.
if ((info->temp_file = _wfopen(path, L"w+bD") ) == NULL)
ERREXITS(cinfo, JERR_TFILE_CREATE, "");
info->read_backing_store = read_backing_store;
info->write_backing_store = write_backing_store;
info->close_backing_store = close_backing_store;
} //jpeg_open_backing_store
/*
* These routines take care of any system-dependent initialization and
* cleanup required.
*/
GLOBAL(long)
jpeg_mem_init (j_common_ptr cinfo)
{
return DEFAULT_MAX_MEM; /* default for max_memory_to_use */
}
GLOBAL(void)
jpeg_mem_term (j_common_ptr cinfo)
{
/* no work */
}
}
I'm intentionally ignoring errors from some of functions - have you ever seen GetTempPathW or GetModuleFileNameW failing ?
A bit of a refresher from the manpage of on tmpfile(), which returns a FILE*:
The file will be automatically deleted when it is closed or the program terminates.
My verdict for this issue: Deleting a file on Windows is weird.
When you delete a file on Windows, for as long as something holds a handle, you can't call CreateFile on something with the same absolute path, otherwise it will fail with the NT error code STATUS_DELETE_PENDING, which gets mapped to the Win32 code ERROR_ACCESS_DENIED. This is probably where EPERM in errno is coming from. You can confirm this with a tool like Sysinternals Process Monitor.
My guess is that CRT somehow wound up creating a file that has the same name as something it's used before. I've sometimes witnessed that deleting files on Windows can appear asynchronous because some other process (sometimes even an antivirus product, in reaction to the fact that you've just closed a delete-on-close handle...) will leave a handle open to the file, so for some timing window you will see a visible file that you can't get a handle to without hitting delete pending/access denied. Or, it could be that tmpfile has simply chosen a filename that some other process is working on.
To avoid this sort of thing you might want to consider another mechanism for temp files... For example a function like Win32 GetTempFileName allows you to create your own prefix which might make a collision less likely. That function appears to resolve race conditions by retrying if a create fails with "already exists", so be careful about deleting the temp filenames that thing generates - deleting the file cancels your rights to use it concurrently with other processes/threads.

Program hangs with no output

I've been poring over this program for ages, and have no idea why it doesn't work. I'm reasonably sure it's doing everything right but instead of actually working it just hangs indefinitely after printing the first prompt, and I just can't figure out why. I'm pretty much at my wit's end now, so if any can suggest what I'm doing wrong, I'd be much obliged...
It's C99, and you'll need the mhash library to compile it (uses for the CRC32 calculation). It's pretty portable but I developed it on Linux. Do not run in a VM!
#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <mhash.h>
/* WARNING: Do not debug this program. Halting on breakpoints at the wrong
* time can be extremely hazardous. YOU HAVE BEEN WARNED. */
/* Structures used to define our layout. Note the careful use of volatile;
* we don't want the compiler optimising away part of the invocation. */
typedef struct
{
const char name[7]; /* sigil at focus */
volatile int target; /* summoning point */
volatile char invocation; /* current char of invocation */
} focus_t;
typedef struct node
{
const char name[4]; /* name of node */
focus_t* center; /* points to the evocation focus */
struct node* cw; /* clockwise binding ring */
struct node* ccw; /* counterclockwise binding ring */
struct node* star; /* next node of star */
const char* linkname; /* name of star linkage */
volatile uint32_t angel; /* protective angel for this node */
} node_t;
/* The pentacle nodes are circularly linked in both directions to form
* a binding perimeter. In addition, they are singly linked to form a
* classic 'daemon trap' five-pointed star. Each node points towards the
* evocation focus (but not the other way around!) to enforce the geometry
* we want. The design is based heavily on the Pentagram of Solomon. */
struct
{
focus_t focus;
node_t node[5];
}
S =
{
/* None of the symbols for the pentacle are in Unicode. So we have to make
* do with Latin transcriptions. */
.focus = { "SOLUZEN", 0 },
.node = {
[0] = { "TE", &S.focus, &S.node[1], &S.node[4], &S.node[2], "BELLONY" },
[1] = { "TRA", &S.focus, &S.node[2], &S.node[0], &S.node[3], "HALLIY" },
[2] = { "GRAM", &S.focus, &S.node[3], &S.node[1], &S.node[4], "HALLIZA" },
[3] = { "MA", &S.focus, &S.node[4], &S.node[2], &S.node[0], "ABDIA" },
[4] = { "TON", &S.focus, &S.node[0], &S.node[3], &S.node[1], "BALLATON" }
}
};
/* Name of spirit to summon --- rot13'd for safety.
* (#65 from Crowley's translation of SHEMHAMPHORASH.)
* This is Andrealphus, he that has dominion over menusuration, astronomy and
* geometry. He seems fairly non-threatening. */
const char spiritname[] = "NAQERNYCUHF";
int rot13(int c) { return 'A' + (((c - 'A') + 13) % 26); }
/* We invoke the following names around the circle as a protective measure.
* Strictly these should be in Hebrew script, but as the computer is a dumb
* instrument we're relying on the symbolism rather than the actual literal
* meaning themselves. Plus, working in RTL is a pain. */
const char* angels[] = {
"Kether", "Eheieh", "Metatron", "Chaioth ha-Qadesh",
"Rashith ha-Gilgalim", "Chokmah", "Jah", "Ratziel", "Auphanim",
"Masloth", "Binah", "Jehovah Elohim", "Tzaphkiel", "Aralim",
"Shabbathai", "Chesed", "El", "Tzadkiel", "Chasmalim", "Tzadekh",
"Geburah", "Elohim Gibor", "Khamael", "Seraphim", "Madim",
"Tiphareth", "Eloah Va-Daath", "Raphael", "Malachim", "Shemesh",
"Netzach", "Jehovah Sabaoth", "Haniel", "Elohim", "Nogah", "Hod",
"Elohim Sabaoth", "Michael", "Beni Elohim", "Kokab", "Yesod",
"Shaddai El Chai", "Gabriel", "Cherubim", "Levanah"
};
const int angelcount = sizeof(angels)/sizeof(*angels);
/* Place the next angel on the pentacle. */
static void updatepentacle()
{
static int angelnode = 0;
static int angelindex = 0;
const char* angel = angels[angelindex++];
angelindex %= angelcount;
/* Hash the angel's name to reduce its essence to 32 bits (which lets us
* copy the angel bodily into the pentacle node. */
uint32_t angelhash;
MHASH td = mhash_init(MHASH_CRC32);
mhash(td, angel, strlen(angel));
mhash_deinit(td, &angelhash);
S.node[angelnode].angel = angelhash;
angelnode = (angelnode + 1) % 5;
}
int main(int argc, const char* argv[])
{
/* Lock the evocation into memory, to prevent it from being paged out
* while the spirit has manifested --- which would be bad. */
int e = mlock(&S, sizeof(S));
if (e != 0)
{
fprintf(stderr, "Unable to lock evocation, refusing to run\n");
exit(1);
}
/* Actually perform the invocation: continually cycle the spirit's
* name into the evocation focus (while maintaining our pentacle
* integrity!) until something shows up in the target of the
* evocation focus. */
printf("Summoning...\n");
do
{
for (int i = 0; i < sizeof(spiritname)-1; i++)
{
S.focus.invocation = rot13(spiritname[i]);
updatepentacle();
usleep(100); /* don't CPU-starve our spirit */
}
}
while (S.focus.target == 0);
printf("Summoning successful! %d\n", S.focus.target);
/* Our spirit's arrived! Dismiss it immediately by using a null
* invocation. Keep going until the evocation focus remains empty.
* FIXME: a particularly mean spirit might find a way to hide. Until
* we can sort this out, only summon relatively benign ones. This is
* probably safe anyway, as when the process terminates the spirit's
* address space will be nuked, taking the spirit with it. */
printf("Dismissing...\n");
do
{
S.focus.target = 0;
for (int i = 0; i < 1000; i++)
{
S.focus.invocation = 0;
updatepentacle();
}
}
while (S.focus.target != 0);
printf("Done.\n");
return 0;
}
Incidentally, shouldn't there be a goetic tag?
Edit: Sorry I haven't gotten back earlier --- after I posted my query last night I ran some more tests and then my computer started making funny burning smells which didn't go away when I switched it off, so I spent the rest of the night tearing it down trying to find which part was faulty. (Didn't find anything.) I'm going to grab some sleep and get back to you. Thanks for the replies!
Edit: I'm posting this from a web café. My house has burnt down. Don't have time to post more but have to warn you: do not run this program for any reason! Really! Not joking! Have to go now, must find sanctuary somewhere---
Edit: 𝕳𝖔𝖈 𝖘𝖙𝖚𝖑𝖙𝖚𝖘 𝖒𝖊𝖚𝖘 𝖊𝖘𝖙. 𝕹𝖔𝖓 𝖎𝖓𝖙𝖊𝖗𝖕𝖔𝖓𝖊 𝖖𝖚𝖎 𝖓𝖔𝖓 𝖎𝖓𝖙𝖊𝖑𝖑𝖎𝖌𝖊𝖗𝖊.
Crux sacra sit mihi lux!
Nunquam draco sit mihi dux.
Vade retro Satana!
Nunquam suade mihi vana!
Sunt mala quae libas.
Ipse venena bibas!
You are definitely lacking a lot of evil features. You should switch to C++ and have a look at the Comp.lang.c++-FAQ on evil features.
I don't know enough about demons and angels, but you must be summoning them incorrectly, since nothing is changing S.focus.target for you.

Resources