mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2025-07-31 19:24:42 +02:00
Added PBKDF2 benchmark. Benchmark improvements to capture results in static buffer (helps benchmarking on systems without printf support). Added benchmark "-print" option to show summary. Added wolfCrypt test version header.
This commit is contained in:
@@ -245,6 +245,8 @@
|
|||||||
#define BENCH_HMAC (BENCH_HMAC_MD5 | BENCH_HMAC_SHA | \
|
#define BENCH_HMAC (BENCH_HMAC_MD5 | BENCH_HMAC_SHA | \
|
||||||
BENCH_HMAC_SHA224 | BENCH_HMAC_SHA256 | \
|
BENCH_HMAC_SHA224 | BENCH_HMAC_SHA256 | \
|
||||||
BENCH_HMAC_SHA384 | BENCH_HMAC_SHA512)
|
BENCH_HMAC_SHA384 | BENCH_HMAC_SHA512)
|
||||||
|
#define BENCH_PBKDF2 0x00000100
|
||||||
|
|
||||||
/* Asymmetric algorithms. */
|
/* Asymmetric algorithms. */
|
||||||
#define BENCH_RSA_KEYGEN 0x00000001
|
#define BENCH_RSA_KEYGEN 0x00000001
|
||||||
#define BENCH_RSA 0x00000002
|
#define BENCH_RSA 0x00000002
|
||||||
@@ -423,6 +425,9 @@ static const bench_alg bench_mac_opt[] = {
|
|||||||
#ifdef WOLFSSL_SHA512
|
#ifdef WOLFSSL_SHA512
|
||||||
{ "-hmac-sha512", BENCH_HMAC_SHA512 },
|
{ "-hmac-sha512", BENCH_HMAC_SHA512 },
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef NO_PWDBASED
|
||||||
|
{ "-pbkdf2", BENCH_PBKDF2 },
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
{ NULL, 0}
|
{ NULL, 0}
|
||||||
};
|
};
|
||||||
@@ -494,7 +499,7 @@ static int lng_index = 0;
|
|||||||
|
|
||||||
#ifndef NO_MAIN_DRIVER
|
#ifndef NO_MAIN_DRIVER
|
||||||
#ifndef MAIN_NO_ARGS
|
#ifndef MAIN_NO_ARGS
|
||||||
static const char* bench_Usage_msg1[][11] = {
|
static const char* bench_Usage_msg1[][12] = {
|
||||||
/* 0 English */
|
/* 0 English */
|
||||||
{ "-? <num> Help, print this usage\n 0: English, 1: Japanese\n",
|
{ "-? <num> Help, print this usage\n 0: English, 1: Japanese\n",
|
||||||
"-csv Print terminal output in csv format\n",
|
"-csv Print terminal output in csv format\n",
|
||||||
@@ -507,6 +512,7 @@ static const char* bench_Usage_msg1[][11] = {
|
|||||||
"-lng <num> Display benchmark result by specified language.\n 0: English, 1: Japanese\n",
|
"-lng <num> Display benchmark result by specified language.\n 0: English, 1: Japanese\n",
|
||||||
"<num> Size of block in bytes\n",
|
"<num> Size of block in bytes\n",
|
||||||
"-threads <num> Number of threads to run\n"
|
"-threads <num> Number of threads to run\n"
|
||||||
|
"-print Show benchmark stats summary\n"
|
||||||
},
|
},
|
||||||
#ifndef NO_MULTIBYTE_PRINT
|
#ifndef NO_MULTIBYTE_PRINT
|
||||||
/* 1 Japanese */
|
/* 1 Japanese */
|
||||||
@@ -521,6 +527,7 @@ static const char* bench_Usage_msg1[][11] = {
|
|||||||
"-lng <num> 指定された言語でベンチマーク結果を表示します。\n 0: 英語、 1: 日本語\n",
|
"-lng <num> 指定された言語でベンチマーク結果を表示します。\n 0: 英語、 1: 日本語\n",
|
||||||
"<num> ブロックサイズをバイト単位で指定します。\n",
|
"<num> ブロックサイズをバイト単位で指定します。\n",
|
||||||
"-threads <num> 実行するスレッド数\n"
|
"-threads <num> 実行するスレッド数\n"
|
||||||
|
"-print ベンチマーク統計の要約を表示する\n"
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
@@ -891,14 +898,42 @@ static THREAD_LS_T byte* bench_iv = NULL;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* This code handles cases with systems where static (non cost) ram variables
|
||||||
|
aren't properly initialized with data */
|
||||||
|
static int gBenchStaticInit = 0;
|
||||||
|
static void benchmark_static_init(void)
|
||||||
|
{
|
||||||
|
if (gBenchStaticInit == 0) {
|
||||||
|
gBenchStaticInit = 1;
|
||||||
|
|
||||||
|
/* Init static variables */
|
||||||
|
bench_all = 1;
|
||||||
|
#ifdef BENCH_EMBEDDED
|
||||||
|
numBlocks = 25; /* how many kB to test (en/de)cryption */
|
||||||
|
bench_size = (1024ul);
|
||||||
|
#else
|
||||||
|
numBlocks = 5; /* how many megs to test (en/de)cryption */
|
||||||
|
bench_size = (1024*1024ul);
|
||||||
|
#endif
|
||||||
|
#if defined(HAVE_AESGCM) || defined(HAVE_AESCCM)
|
||||||
|
aesAuthAddSz = AES_AUTH_ADD_SZ;
|
||||||
|
#endif
|
||||||
|
base2 = 1;
|
||||||
|
digest_stream = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* Begin Stats Functions */
|
/* Begin Stats Functions */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_NO_ASYNC_THREADING)
|
static int gPrintStats = 0;
|
||||||
typedef enum bench_stat_type {
|
typedef enum bench_stat_type {
|
||||||
BENCH_STAT_ASYM,
|
BENCH_STAT_ASYM,
|
||||||
BENCH_STAT_SYM,
|
BENCH_STAT_SYM,
|
||||||
} bench_stat_type_t;
|
} bench_stat_type_t;
|
||||||
|
#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_NO_ASYNC_THREADING)
|
||||||
typedef struct bench_stats {
|
typedef struct bench_stats {
|
||||||
struct bench_stats* next;
|
struct bench_stats* next;
|
||||||
struct bench_stats* prev;
|
struct bench_stats* prev;
|
||||||
@@ -910,6 +945,7 @@ static THREAD_LS_T byte* bench_iv = NULL;
|
|||||||
int finishCount;
|
int finishCount;
|
||||||
bench_stat_type_t type;
|
bench_stat_type_t type;
|
||||||
int lastRet;
|
int lastRet;
|
||||||
|
const char* perftype;
|
||||||
} bench_stats_t;
|
} bench_stats_t;
|
||||||
static bench_stats_t* bench_stats_head;
|
static bench_stats_t* bench_stats_head;
|
||||||
static bench_stats_t* bench_stats_tail;
|
static bench_stats_t* bench_stats_tail;
|
||||||
@@ -917,7 +953,7 @@ static THREAD_LS_T byte* bench_iv = NULL;
|
|||||||
|
|
||||||
static bench_stats_t* bench_stats_add(bench_stat_type_t type,
|
static bench_stats_t* bench_stats_add(bench_stat_type_t type,
|
||||||
const char* algo, int strength, const char* desc, int doAsync,
|
const char* algo, int strength, const char* desc, int doAsync,
|
||||||
double perfsec, int ret)
|
double perfsec, const char* perftype, int ret)
|
||||||
{
|
{
|
||||||
bench_stats_t* bstat;
|
bench_stats_t* bstat;
|
||||||
|
|
||||||
@@ -952,7 +988,6 @@ static THREAD_LS_T byte* bench_iv = NULL;
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bstat) {
|
if (bstat) {
|
||||||
int isLast = 0;
|
|
||||||
bstat->type = type;
|
bstat->type = type;
|
||||||
bstat->algo = algo;
|
bstat->algo = algo;
|
||||||
bstat->strength = strength;
|
bstat->strength = strength;
|
||||||
@@ -960,22 +995,32 @@ static THREAD_LS_T byte* bench_iv = NULL;
|
|||||||
bstat->doAsync = doAsync;
|
bstat->doAsync = doAsync;
|
||||||
bstat->perfsec += perfsec;
|
bstat->perfsec += perfsec;
|
||||||
bstat->finishCount++;
|
bstat->finishCount++;
|
||||||
|
bstat->perftype = perftype;
|
||||||
if (bstat->lastRet > ret)
|
if (bstat->lastRet > ret)
|
||||||
bstat->lastRet = ret; /* track last error */
|
bstat->lastRet = ret; /* track last error */
|
||||||
|
|
||||||
if (bstat->finishCount == g_threadCount) {
|
|
||||||
isLast = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&bench_lock);
|
pthread_mutex_unlock(&bench_lock);
|
||||||
|
|
||||||
/* wait until remaining are complete */
|
/* wait until remaining are complete */
|
||||||
while (bstat->finishCount < g_threadCount) {
|
while (bstat->finishCount < g_threadCount) {
|
||||||
wc_AsyncThreadYield();
|
wc_AsyncThreadYield();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pthread_mutex_unlock(&bench_lock);
|
||||||
|
}
|
||||||
|
|
||||||
/* print final stat */
|
return bstat;
|
||||||
if (isLast) {
|
}
|
||||||
|
|
||||||
|
void bench_stats_print(void)
|
||||||
|
{
|
||||||
|
bench_stats_t* bstat;
|
||||||
|
|
||||||
|
/* protect bench_stats_head and bench_stats_tail access */
|
||||||
|
pthread_mutex_lock(&bench_lock);
|
||||||
|
|
||||||
|
for (bstat = bench_stats_head; bstat != NULL; ) {
|
||||||
if (bstat->type == BENCH_STAT_SYM) {
|
if (bstat->type == BENCH_STAT_SYM) {
|
||||||
printf("%-16s%s %8.3f %s/s\n", bstat->desc,
|
printf("%-16s%s %8.3f %s/s\n", bstat->desc,
|
||||||
BENCH_ASYNC_GET_NAME(bstat->doAsync), bstat->perfsec,
|
BENCH_ASYNC_GET_NAME(bstat->doAsync), bstat->perfsec,
|
||||||
@@ -986,13 +1031,65 @@ static THREAD_LS_T byte* bench_iv = NULL;
|
|||||||
bstat->algo, bstat->strength, bstat->desc,
|
bstat->algo, bstat->strength, bstat->desc,
|
||||||
BENCH_ASYNC_GET_NAME(bstat->doAsync), bstat->perfsec);
|
BENCH_ASYNC_GET_NAME(bstat->doAsync), bstat->perfsec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bstat = bstat->next;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else {
|
|
||||||
pthread_mutex_unlock(&bench_lock);
|
pthread_mutex_unlock(&bench_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
typedef struct bench_stats {
|
||||||
|
const char* algo;
|
||||||
|
const char* desc;
|
||||||
|
double perfsec;
|
||||||
|
const char* perftype;
|
||||||
|
int strength;
|
||||||
|
bench_stat_type_t type;
|
||||||
|
int ret;
|
||||||
|
} bench_stats_t;
|
||||||
|
#define MAX_BENCH_STATS 50
|
||||||
|
static bench_stats_t gStats[MAX_BENCH_STATS];
|
||||||
|
static int gStatsCount;
|
||||||
|
|
||||||
|
static bench_stats_t* bench_stats_add(bench_stat_type_t type,
|
||||||
|
const char* algo, int strength, const char* desc, int doAsync,
|
||||||
|
double perfsec, const char* perftype, int ret)
|
||||||
|
{
|
||||||
|
bench_stats_t* bstat = NULL;
|
||||||
|
if (gStatsCount >= MAX_BENCH_STATS)
|
||||||
return bstat;
|
return bstat;
|
||||||
|
|
||||||
|
bstat = &gStats[gStatsCount++];
|
||||||
|
bstat->algo = algo;
|
||||||
|
bstat->desc = desc;
|
||||||
|
bstat->perfsec = perfsec;
|
||||||
|
bstat->perftype = perftype;
|
||||||
|
bstat->strength = strength;
|
||||||
|
bstat->type = type;
|
||||||
|
bstat->ret = ret;
|
||||||
|
|
||||||
|
(void)doAsync;
|
||||||
|
|
||||||
|
return bstat;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_stats_print(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
bench_stats_t* bstat;
|
||||||
|
for (i=0; i<gStatsCount; i++) {
|
||||||
|
bstat = &gStats[i];
|
||||||
|
if (bstat->type == BENCH_STAT_SYM) {
|
||||||
|
printf("%-16s %8.3f %s/s\n", bstat->desc, bstat->perfsec,
|
||||||
|
base2 ? "MB" : "mB");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("%-5s %4d %-9s %.3f ops/sec\n",
|
||||||
|
bstat->algo, bstat->strength, bstat->desc, bstat->perfsec);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* WOLFSSL_ASYNC_CRYPT && !WC_NO_ASYNC_THREADING */
|
#endif /* WOLFSSL_ASYNC_CRYPT && !WC_NO_ASYNC_THREADING */
|
||||||
|
|
||||||
@@ -1017,6 +1114,7 @@ static WC_INLINE int bench_stats_sym_check(double start)
|
|||||||
return ((current_time(0) - start) < BENCH_MIN_RUNTIME_SEC);
|
return ((current_time(0) - start) < BENCH_MIN_RUNTIME_SEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* countSz is number of bytes that 1 count represents. Normally bench_size,
|
/* countSz is number of bytes that 1 count represents. Normally bench_size,
|
||||||
* except for AES direct that operates on AES_BLOCK_SIZE blocks */
|
* except for AES direct that operates on AES_BLOCK_SIZE blocks */
|
||||||
static void bench_stats_sym_finish(const char* desc, int doAsync, int count,
|
static void bench_stats_sym_finish(const char* desc, int doAsync, int count,
|
||||||
@@ -1084,10 +1182,8 @@ static void bench_stats_sym_finish(const char* desc, int doAsync, int count,
|
|||||||
printf("Benchmark %s failed: %d\n", desc, ret);
|
printf("Benchmark %s failed: %d\n", desc, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_NO_ASYNC_THREADING)
|
|
||||||
/* Add to thread stats */
|
/* Add to thread stats */
|
||||||
bench_stats_add(BENCH_STAT_SYM, NULL, 0, desc, doAsync, persec, ret);
|
bench_stats_add(BENCH_STAT_SYM, NULL, 0, desc, doAsync, persec, blockType, ret);
|
||||||
#endif
|
|
||||||
|
|
||||||
(void)doAsync;
|
(void)doAsync;
|
||||||
(void)ret;
|
(void)ret;
|
||||||
@@ -1102,6 +1198,7 @@ static void bench_stats_asym_finish(const char* algo, int strength,
|
|||||||
{
|
{
|
||||||
double total, each = 0, opsSec, milliEach;
|
double total, each = 0, opsSec, milliEach;
|
||||||
const char **word = bench_result_words2[lng_index];
|
const char **word = bench_result_words2[lng_index];
|
||||||
|
const char* kOpsSec = "Ops/Sec";
|
||||||
|
|
||||||
total = current_time(0) - start;
|
total = current_time(0) - start;
|
||||||
if (count > 0)
|
if (count > 0)
|
||||||
@@ -1129,10 +1226,8 @@ static void bench_stats_asym_finish(const char* algo, int strength,
|
|||||||
printf("Benchmark %s %s %d failed: %d\n", algo, desc, strength, ret);
|
printf("Benchmark %s %s %d failed: %d\n", algo, desc, strength, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_NO_ASYNC_THREADING)
|
|
||||||
/* Add to thread stats */
|
/* Add to thread stats */
|
||||||
bench_stats_add(BENCH_STAT_ASYM, algo, strength, desc, doAsync, opsSec, ret);
|
bench_stats_add(BENCH_STAT_ASYM, algo, strength, desc, doAsync, opsSec, kOpsSec, ret);
|
||||||
#endif
|
|
||||||
|
|
||||||
(void)doAsync;
|
(void)doAsync;
|
||||||
(void)ret;
|
(void)ret;
|
||||||
@@ -1546,6 +1641,11 @@ static void* benchmarks_do(void* args)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef NO_PWDBASED
|
||||||
|
if (bench_all || (bench_mac_algs & BENCH_PBKDF2)) {
|
||||||
|
bench_pbkdf2();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif /* NO_HMAC */
|
#endif /* NO_HMAC */
|
||||||
|
|
||||||
#ifdef HAVE_SCRYPT
|
#ifdef HAVE_SCRYPT
|
||||||
@@ -1698,6 +1798,8 @@ int benchmark_init(void)
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
benchmark_static_init();
|
||||||
|
|
||||||
#ifdef WOLFSSL_STATIC_MEMORY
|
#ifdef WOLFSSL_STATIC_MEMORY
|
||||||
ret = wc_LoadStaticMemory(&HEAP_HINT, gBenchMemory, sizeof(gBenchMemory),
|
ret = wc_LoadStaticMemory(&HEAP_HINT, gBenchMemory, sizeof(gBenchMemory),
|
||||||
WOLFMEM_GENERAL, 1);
|
WOLFMEM_GENERAL, 1);
|
||||||
@@ -1749,6 +1851,10 @@ int benchmark_free(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (gPrintStats || devId != INVALID_DEVID) {
|
||||||
|
bench_stats_print();
|
||||||
|
}
|
||||||
|
|
||||||
bench_stats_free();
|
bench_stats_free();
|
||||||
|
|
||||||
if ((ret = wolfCrypt_Cleanup()) != 0) {
|
if ((ret = wolfCrypt_Cleanup()) != 0) {
|
||||||
@@ -3974,6 +4080,28 @@ void bench_hmac_sha512(int doAsync)
|
|||||||
|
|
||||||
#endif /* WOLFSSL_SHA512 */
|
#endif /* WOLFSSL_SHA512 */
|
||||||
|
|
||||||
|
#ifndef NO_PWDBASED
|
||||||
|
void bench_pbkdf2(void)
|
||||||
|
{
|
||||||
|
double start;
|
||||||
|
int ret = 0, count = 0;
|
||||||
|
const char* passwd32 = "passwordpasswordpasswordpassword";
|
||||||
|
const byte salt32[] = { 0x78, 0x57, 0x8E, 0x5a, 0x5d, 0x63, 0xcb, 0x06,
|
||||||
|
0x78, 0x57, 0x8E, 0x5a, 0x5d, 0x63, 0xcb, 0x06,
|
||||||
|
0x78, 0x57, 0x8E, 0x5a, 0x5d, 0x63, 0xcb, 0x06,
|
||||||
|
0x78, 0x57, 0x8E, 0x5a, 0x5d, 0x63, 0xcb, 0x06 };
|
||||||
|
byte derived[32];
|
||||||
|
|
||||||
|
bench_stats_start(&count, &start);
|
||||||
|
do {
|
||||||
|
ret = wc_PBKDF2(derived, (const byte*)passwd32, (int)XSTRLEN(passwd32),
|
||||||
|
salt32, (int)sizeof(salt32), 1000, 32, WC_SHA256);
|
||||||
|
count++;
|
||||||
|
} while (bench_stats_sym_check(start));
|
||||||
|
bench_stats_sym_finish("PBKDF2", 32, count, 32, start, ret);
|
||||||
|
}
|
||||||
|
#endif /* !NO_PWDBASED */
|
||||||
|
|
||||||
#endif /* NO_HMAC */
|
#endif /* NO_HMAC */
|
||||||
|
|
||||||
#ifndef NO_RSA
|
#ifndef NO_RSA
|
||||||
@@ -5582,6 +5710,7 @@ static void Usage(void)
|
|||||||
#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_NO_ASYNC_THREADING)
|
#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_NO_ASYNC_THREADING)
|
||||||
printf("%s", bench_Usage_msg1[lng_index][10]); /* option -threads <num> */
|
printf("%s", bench_Usage_msg1[lng_index][10]); /* option -threads <num> */
|
||||||
#endif
|
#endif
|
||||||
|
printf("%s", bench_Usage_msg1[lng_index][11]); /* option -print */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Match the command line argument with the string.
|
/* Match the command line argument with the string.
|
||||||
@@ -5617,6 +5746,8 @@ int main(int argc, char** argv)
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
benchmark_static_init();
|
||||||
|
|
||||||
#ifndef MAIN_NO_ARGS
|
#ifndef MAIN_NO_ARGS
|
||||||
while (argc > 1) {
|
while (argc > 1) {
|
||||||
if (string_matches(argv[1], "-?")) {
|
if (string_matches(argv[1], "-?")) {
|
||||||
@@ -5679,6 +5810,9 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
else if (string_matches(argv[1], "-print")) {
|
||||||
|
gPrintStats = 1;
|
||||||
|
}
|
||||||
else if (argv[1][0] == '-') {
|
else if (argv[1][0] == '-') {
|
||||||
optMatched = 0;
|
optMatched = 0;
|
||||||
#ifndef WOLFSSL_BENCHMARK_ALL
|
#ifndef WOLFSSL_BENCHMARK_ALL
|
||||||
|
@@ -92,6 +92,9 @@ void bench_ntruKeyGen(void);
|
|||||||
void bench_rng(void);
|
void bench_rng(void);
|
||||||
void bench_blake2b(void);
|
void bench_blake2b(void);
|
||||||
void bench_blake2s(void);
|
void bench_blake2s(void);
|
||||||
|
void bench_pbkdf2(void);
|
||||||
|
|
||||||
|
void bench_stats_print(void);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@@ -503,6 +503,10 @@ int wolfcrypt_test(void* args)
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
printf("------------------------------------------------------------------------------\n");
|
||||||
|
printf(" wolfSSL version %s\n", LIBWOLFSSL_VERSION_STRING);
|
||||||
|
printf("------------------------------------------------------------------------------\n");
|
||||||
|
|
||||||
if (args)
|
if (args)
|
||||||
((func_args*)args)->return_code = -1; /* error state */
|
((func_args*)args)->return_code = -1; /* error state */
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user